From b37cbe40b25914bf273ebdc1780fc2cc58280153 Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Thu, 7 Aug 2025 09:35:50 +0200 Subject: [PATCH 1/7] add goldbach prebid adapter --- adapters/goldbach/goldbach.go | 232 ++++++++++++++++++ adapters/goldbach/goldbach_test.go | 39 +++ .../goldbachtest/exemplary/banner.json | 128 ++++++++++ .../goldbachtest/exemplary/mixed.json | 187 ++++++++++++++ .../exemplary/multiple-publisher.json | 221 +++++++++++++++++ .../goldbachtest/exemplary/native.json | 121 +++++++++ .../goldbachtest/exemplary/video.json | 137 +++++++++++ .../goldbachtest/supplemental/204.json | 72 ++++++ .../goldbachtest/supplemental/500.json | 77 ++++++ .../supplemental/empty-publisher-id.json | 38 +++ .../supplemental/empty-slot-id.json | 38 +++ .../supplemental/invalid-bid-ext.json | 33 +++ .../supplemental/invalid-bidder-ext.json | 35 +++ .../supplemental/invalid-request-ext.json | 81 ++++++ .../supplemental/invalid-response.json | 100 ++++++++ .../supplemental/no-bid-type-response.json | 111 +++++++++ .../supplemental/no-bidder-response.json | 108 ++++++++ adapters/goldbach/params_test.go | 62 +++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_goldbach.go | 35 +++ static/bidder-info/goldbach.yaml | 15 ++ static/bidder-params/goldbach.json | 38 +++ 23 files changed, 1912 insertions(+) create mode 100644 adapters/goldbach/goldbach.go create mode 100644 adapters/goldbach/goldbach_test.go create mode 100644 adapters/goldbach/goldbachtest/exemplary/banner.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/mixed.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/native.json create mode 100644 adapters/goldbach/goldbachtest/exemplary/video.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/204.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/500.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/invalid-response.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json create mode 100644 adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json create mode 100644 adapters/goldbach/params_test.go create mode 100644 openrtb_ext/imp_goldbach.go create mode 100644 static/bidder-info/goldbach.yaml create mode 100644 static/bidder-params/goldbach.json diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go new file mode 100644 index 00000000000..c1057c0251c --- /dev/null +++ b/adapters/goldbach/goldbach.go @@ -0,0 +1,232 @@ +package goldbach + +import ( + "errors" + "fmt" + "net/http" + + "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/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +type requestExtAdapter struct { + Goldbach requestExtGoldbach `json:"goldbach"` + + *openrtb_ext.ExtRequest `json:",inline,omitempty"` +} + +type requestExtGoldbach struct { + PublisherID string `json:"publisherId"` + MockResponse *bool `json:"mockResponse,omitempty"` +} + +type impExtAdapter struct { + Goldbach impExtGoldbachOutgoing `json:"goldbach"` +} + +type impExtGoldbachOutgoing struct { + Targetings map[string]openrtb_ext.ImpExtGoldbachTargetingValue `json:"targetings,omitempty"` + SlotID string `json:"slotId"` +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + if config.Endpoint == "" { + return nil, errors.New("missing endpoint adapter parameter") + } + + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var reqs []*adapters.RequestData + var errs []error + + var requestExt requestExtAdapter + if request.Ext != nil { + if err := jsonutil.Unmarshal(request.Ext, &requestExt); err != nil { + errs = append(errs, fmt.Errorf("unable to unmarshal request.ext: %v", err)) + } + } + + // group impressions by publisher ID + publisherImps := make(map[string][]openrtb2.Imp) + for _, imp := range request.Imp { + publisherID, impCopy, err := buildImp(imp) + if err != nil { + errs = append(errs, err) + continue + } + + publisherImps[publisherID] = append(publisherImps[publisherID], impCopy) + } + + if len(publisherImps) == 0 { + errs = append(errs, errors.New("no publisher ID found in impressions")) + } + + // create a separate request for each publisher + for publisherID, imps := range publisherImps { + requestPublisher, err := buildRequest(*request, publisherID, &imps, &requestExt) + if err != nil { + errs = append(errs, err) + continue + } + + resJSON, err := jsonutil.Marshal(&requestPublisher) + if err != nil { + errs = append(errs, fmt.Errorf("unable to marshal request: %v", err)) + continue + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + req := &adapters.RequestData{ + Method: "POST", + Uri: a.endpoint, + Body: resJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestPublisher.Imp), + } + + reqs = append(reqs, req) + } + + return reqs, errs +} + +func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.RequestData, httpRes *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if httpRes.StatusCode == http.StatusNoContent { + return nil, nil + } + + if httpRes.StatusCode != http.StatusCreated { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("unexpected status code: %d. Run with request.debug = 1 for more info", httpRes.StatusCode), + }} + } + + var resp openrtb2.BidResponse + if err := jsonutil.Unmarshal(httpRes.Body, &resp); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("unable to unmarshal response: %s", err), + }} + } + + bidderResponse := adapters.NewBidderResponse() + bidderResponse.Currency = resp.Cur + + var errs []error + for _, sb := range resp.SeatBid { + for i := range sb.Bid { + bidType, err := getBidMediaType(&sb.Bid[i]) + if err != nil { + errs = append(errs, err) + continue + } + + bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + }) + } + } + + if len(bidderResponse.Bids) == 0 { + errs = append(errs, &errortypes.BadServerResponse{ + Message: "no valid bids found in response", + }) + return nil, errs + } + + return bidderResponse, errs +} + +func buildImp(imp openrtb2.Imp) (string, openrtb2.Imp, error) { + impExt, err := extractImpExt(&imp) + if err != nil { + return "", openrtb2.Imp{}, err + } + + imp.Ext, err = jsonutil.Marshal(&impExtAdapter{ + Goldbach: impExtGoldbachOutgoing{ + Targetings: impExt.CustomTargeting, + SlotID: impExt.SlotID, + }, + }) + + if err != nil { + return "", openrtb2.Imp{}, fmt.Errorf("unable to marshal imp.ext: %v", err) + } + + return impExt.PublisherID, imp, nil +} + +func extractImpExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtGoldbach, error) { + var extImpBidder adapters.ExtImpBidder + if err := jsonutil.Unmarshal(imp.Ext, &extImpBidder); err != nil { + return nil, &errortypes.BadInput{ + Message: "unable to unmarshal imp.ext", + } + } + + var goldbachExt openrtb_ext.ImpExtGoldbach + if err := jsonutil.Unmarshal(extImpBidder.Bidder, &goldbachExt); err != nil { + return nil, &errortypes.BadInput{ + Message: "unable to unmarshal imp.ext.bidder", + } + } + + if len(goldbachExt.PublisherID) == 0 || len(goldbachExt.SlotID) == 0 { + return nil, &errortypes.BadInput{ + Message: "publisherId and slotId are required", + } + } + return &goldbachExt, nil +} + +func buildRequest(request openrtb2.BidRequest, publisherID string, imps *[]openrtb2.Imp, requestExt *requestExtAdapter) (*openrtb2.BidRequest, error) { + request.Imp = *imps + request.ID = fmt.Sprintf("%s_%s", request.ID, publisherID) + + // Set the publisher ID in the request.ext + requestPublisherExt, err := jsonutil.Marshal(&requestExtAdapter{ + Goldbach: requestExtGoldbach{ + PublisherID: publisherID, + MockResponse: requestExt.Goldbach.MockResponse, + }, + ExtRequest: requestExt.ExtRequest, + }) + if err != nil { + return nil, fmt.Errorf("unable to marshal request.ext: %v", err) + } + + request.Ext = requestPublisherExt + + return &request, nil +} + +func getBidMediaType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + var extBid openrtb_ext.ExtBid + if err := jsonutil.Unmarshal(bid.Ext, &extBid); err != nil { + return "", fmt.Errorf("unable to unmarshal ext for bid %v", bid.ID) + } + + if extBid.Prebid == nil || len(extBid.Prebid.Type) == 0 { + return "", fmt.Errorf("no media type for bid %v", bid.ID) + } + + return extBid.Prebid.Type, nil +} diff --git a/adapters/goldbach/goldbach_test.go b/adapters/goldbach/goldbach_test.go new file mode 100644 index 00000000000..d8a12efc4c6 --- /dev/null +++ b/adapters/goldbach/goldbach_test.go @@ -0,0 +1,39 @@ +package goldbach + +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" +) + +func TestJsonSamples(t *testing.T) { + _, buildErr := Builder( + openrtb_ext.BidderGoldbach, + config.Adapter{}, + config.Server{}, + ) + + if buildErr == nil { + t.Fatalf("Builder should have returned error") + } + + bidder, buildErr := Builder( + openrtb_ext.BidderGoldbach, + config.Adapter{ + Endpoint: "https://gold.bach/prebid/adapter-endpoint", + }, + config.Server{ + ExternalUrl: "http://hosturl.com", + GvlID: 1, + DataCenter: "2", + }, + ) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "goldbachtest", bidder) +} diff --git a/adapters/goldbach/goldbachtest/exemplary/banner.json b/adapters/goldbach/goldbachtest/exemplary/banner.json new file mode 100644 index 00000000000..23bbc5ef35f --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/banner.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": {}, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/mixed.json b/adapters/goldbach/goldbachtest/exemplary/mixed.json new file mode 100644 index 00000000000..2f6995b728e --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/mixed.json @@ -0,0 +1,187 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + }, + { + "id": "test-imp-456", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + }, + { + "id": "test-imp-456", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123", "test-imp-456"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + { + "id": "da2048d1-d8a2-425a-9f36-df62e04319ae", + "price": 2.5, + "impid": "test-imp-456", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + }, + { + "bid": { + "id": "da2048d1-d8a2-425a-9f36-df62e04319ae", + "price": 2.5, + "impid": "test-imp-456", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json b/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json new file mode 100644 index 00000000000..3ccf1061163 --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/multiple-publisher.json @@ -0,0 +1,221 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + }, + { + "id": "test-imp-987", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/fr-example.ch/slot-id/some-page", + "publisherId": "fr-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + }, + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/fr-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-987", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "fr-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_fr-example.ch" + }, + "impIDs": ["test-imp-987"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "cbf0cb64-f86b-4a31-a7c3-3904fa32d168", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-987", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "cbf0cb64-f86b-4a31-a7c3-3904fa32d168", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-987", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/native.json b/adapters/goldbach/goldbachtest/exemplary/native.json new file mode 100644 index 00000000000..2c9c797ca6b --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/native.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "id": "test-imp-123", + "native": { + "request": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"img\":{\"type\":3}},{\"id\":1,\"required\":1,\"title\":{\"len\":140}},{\"id\":2,\"required\":1,\"data\":{\"type\":2}},{\"id\":3,\"required\":0,\"img\":{\"type\":1}},{\"id\":4,\"required\":0,\"data\":{\"type\":12}},{\"id\":5,\"required\":0,\"data\":{\"type\":1}}]}", + "ver": "1.2" + }, + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "price": 2.5, + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/exemplary/video.json b/adapters/goldbach/goldbachtest/exemplary/video.json new file mode 100644 index 00000000000..7eaed83320b --- /dev/null +++ b/adapters/goldbach/goldbachtest/exemplary/video.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest": { + "imp": [ + { + "video": { + "api": [1, 2], + "mimes": ["video/mp4", "application/javascript"], + "protocols": [2, 3, 5, 6, 7, 8], + "playbackmethod": [6], + "plcmt": 4, + "w": 640, + "h": 480 + }, + "id": "test-imp-123", + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "video": { + "api": [1, 2], + "mimes": ["video/mp4", "application/javascript"], + "protocols": [2, 3, 5, 6, 7, 8], + "playbackmethod": [6], + "plcmt": 4, + "w": 640, + "h": 480 + }, + "id": "test-imp-123", + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "impid": "test-imp-123", + "price": 13.5, + "adm": "test-ad-content", + "adid": "456", + "crid": "1234", + "w": 640, + "h": 480, + "ext": { + "prebid": { + "type": "video" + } + } + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "CHF", + "bids": [ + { + "bid": { + "id": "b334cb75-41d8-4f61-801c-1e785a2fe38d", + "impid": "test-imp-123", + "price": 13.5, + "adm": "test-ad-content", + "adid": "456", + "crid": "1234", + "w": 640, + "h": 480, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/204.json b/adapters/goldbach/goldbachtest/supplemental/204.json new file mode 100644 index 00000000000..1a673faa218 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/204.json @@ -0,0 +1,72 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/500.json b/adapters/goldbach/goldbachtest/supplemental/500.json new file mode 100644 index 00000000000..3922de7f018 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/500.json @@ -0,0 +1,77 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 500 + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json b/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json new file mode 100644 index 00000000000..4f0f3c71295 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "publisherId and slotId are required", + "comparison": "literal" + }, + { + "value": "no publisher ID found in impressions", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json b/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json new file mode 100644 index 00000000000..f9c3cfd2083 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json @@ -0,0 +1,38 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "publisherId and slotId are required", + "comparison": "literal" + }, + { + "value": "no publisher ID found in impressions", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json new file mode 100644 index 00000000000..fce52d31c84 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": "invalid bid ext" + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "unable to unmarshal imp.ext", + "comparison": "literal" + }, + { + "value": "no publisher ID found in impressions", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json new file mode 100644 index 00000000000..681f7242ae7 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json @@ -0,0 +1,35 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": "invalid bid ext" + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "unable to unmarshal imp.ext.bidder", + "comparison": "literal" + }, + { + "value": "no publisher ID found in impressions", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json new file mode 100644 index 00000000000..3ea36effc04 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-request-ext.json @@ -0,0 +1,81 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": "invalid request ext" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "^unable to unmarshal request.ext:", + "comparison": "regex" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-response.json b/adapters/goldbach/goldbachtest/supplemental/invalid-response.json new file mode 100644 index 00000000000..b7dd6210b7a --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-response.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch" + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page" + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": { + "bid": [ + { + "id": "test-bid-123", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": { + "type": "banner" + } + } + } + ] + } + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "^unable to unmarshal response:", + "comparison": "regex" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json b/adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json new file mode 100644 index 00000000000..9379a056a81 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/no-bid-type-response.json @@ -0,0 +1,111 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-123", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234", + "ext": { + "prebid": {} + } + } + ] + } + ] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "no media type for bid test-bid-123", + "comparison": "literal" + }, + { + "value": "no valid bids found in response", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json b/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json new file mode 100644 index 00000000000..a88f7279771 --- /dev/null +++ b/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "imp": [ + { + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + }, + "ext": { + "bidder": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "publisherId": "de-example.ch", + "customTargeting": { + "key1": "value1", + "key2": ["value2", "value3"] + } + } + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663" + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Accept": ["application/json"], + "Content-Type": ["application/json;charset=utf-8"] + }, + "uri": "https://gold.bach/prebid/adapter-endpoint", + "body": { + "imp": [ + { + "ext": { + "goldbach": { + "slotId": "12345678/de-example.ch/slot-id/some-page", + "targetings": { + "key1": ["value1"], + "key2": ["value2", "value3"] + } + } + }, + "id": "test-imp-123", + "banner": { + "h": 250, + "w": 300, + "pos": 0 + } + } + ], + "site": { + "page": "https://www.example.ch/" + }, + "device": { + "ua": "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36" + }, + "ext": { + "goldbach": { + "publisherId": "de-example.ch" + } + }, + "id": "723f8906-7f59-4f50-bba9-ed9115ab1663_de-example.ch" + }, + "impIDs": ["test-imp-123"] + }, + "mockResponse": { + "status": 201, + "headers": {}, + "body": { + "id": "c04f2011-87e9-4cde-9152-78fa2a63078a", + "seatbid": [ + { + "bid": [ + { + "id": "test-bid-123", + "price": 2.5, + "adm": "test-ad-content", + "adid": "456", + "impid": "test-imp-123", + "crid": "1234", + "cid": "1234" + } + ] + } + ] + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "unable to unmarshal ext for bid test-bid-123", + "comparison": "literal" + }, + { + "value": "no valid bids found in response", + "comparison": "literal" + } + ] +} diff --git a/adapters/goldbach/params_test.go b/adapters/goldbach/params_test.go new file mode 100644 index 00000000000..502b2cd5deb --- /dev/null +++ b/adapters/goldbach/params_test.go @@ -0,0 +1,62 @@ +package goldbach + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/goldbach.json + +// TestValidParams makes sure that the goldbach schema accepts all imp.ext fields which we intend to support. + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, validParam := range validParams { + if err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected goldbach params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the goldbach schema rejects all the imp.ext fields we don't support. +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"publisherId":"123","slotId":"333"}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":"value1","key2":["value2","value3"]}}`, +} + +var invalidParams = []string{ + `4.2`, + `5`, + `[]`, + ``, + `null`, + `true`, + `{}`, + `{"publisherId":123,"slotId":"333"}`, + `{"publisherId":"123","slotId":333}`, + `{"publisherId":"1234"}`, + `{"slotId":"abc"}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":123,"key2":["value2","value3"]}}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":false,"key2":["value2","value3"]}}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":"value1","key2":[123,456]}}`, + `{"publisherId":"123","slotId":"333","customTargeting":{"key1":"value1","key2":[true,false]}}`, +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index e025eb0ed3c..3b33a75b184 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -114,6 +114,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/gamma" "github.com/prebid/prebid-server/v3/adapters/gamoshi" "github.com/prebid/prebid-server/v3/adapters/globalsun" + "github.com/prebid/prebid-server/v3/adapters/goldbach" "github.com/prebid/prebid-server/v3/adapters/gothamads" "github.com/prebid/prebid-server/v3/adapters/grid" "github.com/prebid/prebid-server/v3/adapters/gumgum" @@ -380,6 +381,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderGamma: gamma.Builder, openrtb_ext.BidderGamoshi: gamoshi.Builder, openrtb_ext.BidderGlobalsun: globalsun.Builder, + openrtb_ext.BidderGoldbach: goldbach.Builder, openrtb_ext.BidderGothamads: gothamads.Builder, openrtb_ext.BidderGrid: grid.Builder, openrtb_ext.BidderGumGum: gumgum.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index cdb6dcd2c7c..c8304943308 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -131,6 +131,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderGamma, BidderGamoshi, BidderGlobalsun, + BidderGoldbach, BidderGothamads, BidderGrid, BidderGumGum, @@ -503,6 +504,7 @@ const ( BidderGamma BidderName = "gamma" BidderGamoshi BidderName = "gamoshi" BidderGlobalsun BidderName = "globalsun" + BidderGoldbach BidderName = "goldbach" BidderGothamads BidderName = "gothamads" BidderGrid BidderName = "grid" BidderGumGum BidderName = "gumgum" diff --git a/openrtb_ext/imp_goldbach.go b/openrtb_ext/imp_goldbach.go new file mode 100644 index 00000000000..c2efd7d750b --- /dev/null +++ b/openrtb_ext/imp_goldbach.go @@ -0,0 +1,35 @@ +package openrtb_ext + +import ( + "fmt" + + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type ImpExtGoldbach struct { + PublisherID string `json:"publisherId"` + SlotID string `json:"slotId"` + CustomTargeting map[string]ImpExtGoldbachTargetingValue `json:"customTargeting,omitempty"` +} + +// custom targeting values can be a single string or an array of strings +type ImpExtGoldbachTargetingValue []string + +func (t *ImpExtGoldbachTargetingValue) UnmarshalJSON(b []byte) error { + // try to unmarshal as a single string first + var stringResult string + if err := jsonutil.UnmarshalValid(b, &stringResult); err == nil { + *t = []string{stringResult} + return nil + } + + // then try to unmarshal as an array of strings + var arrayResult []string + if err := jsonutil.UnmarshalValid(b, &arrayResult); err == nil { + *t = arrayResult + return nil + } + + // if both attempts fail, return an error + return fmt.Errorf("targeting values must be a string or an array of strings, got %s", b) +} diff --git a/static/bidder-info/goldbach.yaml b/static/bidder-info/goldbach.yaml new file mode 100644 index 00000000000..15c59cb5c3b --- /dev/null +++ b/static/bidder-info/goldbach.yaml @@ -0,0 +1,15 @@ +endpoint: "https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction" +maintainer: + email: "simon.aebli@goldbach.com" +gvlVendorID: 580 +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native diff --git a/static/bidder-params/goldbach.json b/static/bidder-params/goldbach.json new file mode 100644 index 00000000000..8958db13cfc --- /dev/null +++ b/static/bidder-params/goldbach.json @@ -0,0 +1,38 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Goldbach Adapter Params", + "description": "A schema which validates params accepted by the Goldbach adapter", + + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "minLength": 1, + "description": "Publisher Environment ID" + }, + "slotId": { + "type": "string", + "minLength": 1, + "description": "Slot Id" + }, + "customTargeting": { + "type": "object", + "description": "Custom Targeting Parameters", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + } + }, + + "required": ["publisherId", "slotId"] +} From 8e986b1dab04f6a07e41e4eed87e1c31c6716bff Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Thu, 4 Sep 2025 11:25:10 +0200 Subject: [PATCH 2/7] contribute StringOrStringArray to util/jsonutil --- adapters/goldbach/goldbach.go | 4 +-- openrtb_ext/imp_goldbach.go | 26 +------------- util/jsonutil/stringOrStringArray.go | 27 +++++++++++++++ util/jsonutil/stringOrStringArray_test.go | 42 +++++++++++++++++++++++ 4 files changed, 72 insertions(+), 27 deletions(-) create mode 100644 util/jsonutil/stringOrStringArray.go create mode 100644 util/jsonutil/stringOrStringArray_test.go diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go index c1057c0251c..3fc4bb48748 100644 --- a/adapters/goldbach/goldbach.go +++ b/adapters/goldbach/goldbach.go @@ -33,8 +33,8 @@ type impExtAdapter struct { } type impExtGoldbachOutgoing struct { - Targetings map[string]openrtb_ext.ImpExtGoldbachTargetingValue `json:"targetings,omitempty"` - SlotID string `json:"slotId"` + Targetings map[string]jsonutil.StringOrStringArray `json:"targetings,omitempty"` + SlotID string `json:"slotId"` } func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { diff --git a/openrtb_ext/imp_goldbach.go b/openrtb_ext/imp_goldbach.go index c2efd7d750b..3452695fef8 100644 --- a/openrtb_ext/imp_goldbach.go +++ b/openrtb_ext/imp_goldbach.go @@ -1,35 +1,11 @@ package openrtb_ext import ( - "fmt" - "github.com/prebid/prebid-server/v3/util/jsonutil" ) type ImpExtGoldbach struct { PublisherID string `json:"publisherId"` SlotID string `json:"slotId"` - CustomTargeting map[string]ImpExtGoldbachTargetingValue `json:"customTargeting,omitempty"` -} - -// custom targeting values can be a single string or an array of strings -type ImpExtGoldbachTargetingValue []string - -func (t *ImpExtGoldbachTargetingValue) UnmarshalJSON(b []byte) error { - // try to unmarshal as a single string first - var stringResult string - if err := jsonutil.UnmarshalValid(b, &stringResult); err == nil { - *t = []string{stringResult} - return nil - } - - // then try to unmarshal as an array of strings - var arrayResult []string - if err := jsonutil.UnmarshalValid(b, &arrayResult); err == nil { - *t = arrayResult - return nil - } - - // if both attempts fail, return an error - return fmt.Errorf("targeting values must be a string or an array of strings, got %s", b) + CustomTargeting map[string]jsonutil.StringOrStringArray `json:"customTargeting,omitempty"` } diff --git a/util/jsonutil/stringOrStringArray.go b/util/jsonutil/stringOrStringArray.go new file mode 100644 index 00000000000..322522d31e3 --- /dev/null +++ b/util/jsonutil/stringOrStringArray.go @@ -0,0 +1,27 @@ +package jsonutil + +import ( + "errors" +) + +type StringOrStringArray []string + +// parse string or string array input into string array +func (t *StringOrStringArray) UnmarshalJSON(b []byte) error { + // try to unmarshal as a single string first + var stringResult string + if err := UnmarshalValid(b, &stringResult); err == nil { + *t = []string{stringResult} + return nil + } + + // then try to unmarshal as an array of strings + var arrayResult []string + if err := UnmarshalValid(b, &arrayResult); err == nil { + *t = arrayResult + return nil + } + + // if both attempts fail, return an error + return errors.New("value should be of type string or []string") +} diff --git a/util/jsonutil/stringOrStringArray_test.go b/util/jsonutil/stringOrStringArray_test.go new file mode 100644 index 00000000000..a88c195d4c5 --- /dev/null +++ b/util/jsonutil/stringOrStringArray_test.go @@ -0,0 +1,42 @@ +package jsonutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestStringOrStringArrayUnmarshalJSON(t *testing.T) { + type Item struct { + Item StringOrStringArray `json:"item"` + } + + t.Run("string", func(t *testing.T) { + jsonData := []byte(`{"item":"hello"}`) + var item Item + assert.NoError(t, UnmarshalValid(jsonData, &item)) + assert.Equal(t, "hello", item.Item[0]) + }) + + t.Run("string_array", func(t *testing.T) { + jsonData := []byte(`{"item":["hello","world"]}`) + var item Item + assert.NoError(t, UnmarshalValid(jsonData, &item)) + assert.Equal(t, "hello", item.Item[0]) + assert.Equal(t, "world", item.Item[1]) + }) + + t.Run("empty_array", func(t *testing.T) { + jsonData := []byte(`{"item": []}`) + var item Item + assert.NoError(t, UnmarshalValid(jsonData, &item)) + assert.Empty(t, item.Item) + }) + + t.Run("invalid_input", func(t *testing.T) { + jsonData := []byte(`{"item":true}`) + var item Item + err := UnmarshalValid(jsonData, &item) + assert.EqualError(t, err, "cannot unmarshal jsonutil.Item.Item: value should be of type string or []string") + }) +} From e02318bad75a0bdee75d0871fee3240df87b2ed8 Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Thu, 4 Sep 2025 13:26:22 +0200 Subject: [PATCH 3/7] add engineering email address --- static/bidder-info/goldbach.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/bidder-info/goldbach.yaml b/static/bidder-info/goldbach.yaml index 15c59cb5c3b..2b8b57393ee 100644 --- a/static/bidder-info/goldbach.yaml +++ b/static/bidder-info/goldbach.yaml @@ -1,6 +1,6 @@ endpoint: "https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction" maintainer: - email: "simon.aebli@goldbach.com" + email: "engineering@goldbach.com" gvlVendorID: 580 capabilities: app: From dd4a83317d306caada819912d992ed8766867db3 Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Tue, 16 Sep 2025 08:30:46 +0200 Subject: [PATCH 4/7] make stringOrStringArray generic --- adapters/goldbach/goldbach.go | 4 +- openrtb_ext/imp_goldbach.go | 6 +- util/jsonutil/itemOrItemArray.go | 27 ++++++++ util/jsonutil/itemOrItemArray_test.go | 83 +++++++++++++++++++++++ util/jsonutil/stringOrStringArray.go | 27 -------- util/jsonutil/stringOrStringArray_test.go | 42 ------------ 6 files changed, 115 insertions(+), 74 deletions(-) create mode 100644 util/jsonutil/itemOrItemArray.go create mode 100644 util/jsonutil/itemOrItemArray_test.go delete mode 100644 util/jsonutil/stringOrStringArray.go delete mode 100644 util/jsonutil/stringOrStringArray_test.go diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go index 3fc4bb48748..48e62f42034 100644 --- a/adapters/goldbach/goldbach.go +++ b/adapters/goldbach/goldbach.go @@ -33,8 +33,8 @@ type impExtAdapter struct { } type impExtGoldbachOutgoing struct { - Targetings map[string]jsonutil.StringOrStringArray `json:"targetings,omitempty"` - SlotID string `json:"slotId"` + Targetings map[string]jsonutil.ItemOrItemArray[string] `json:"targetings,omitempty"` + SlotID string `json:"slotId"` } func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { diff --git a/openrtb_ext/imp_goldbach.go b/openrtb_ext/imp_goldbach.go index 3452695fef8..6c005bcb910 100644 --- a/openrtb_ext/imp_goldbach.go +++ b/openrtb_ext/imp_goldbach.go @@ -5,7 +5,7 @@ import ( ) type ImpExtGoldbach struct { - PublisherID string `json:"publisherId"` - SlotID string `json:"slotId"` - CustomTargeting map[string]jsonutil.StringOrStringArray `json:"customTargeting,omitempty"` + PublisherID string `json:"publisherId"` + SlotID string `json:"slotId"` + CustomTargeting map[string]jsonutil.ItemOrItemArray[string] `json:"customTargeting,omitempty"` } diff --git a/util/jsonutil/itemOrItemArray.go b/util/jsonutil/itemOrItemArray.go new file mode 100644 index 00000000000..854bd67a8be --- /dev/null +++ b/util/jsonutil/itemOrItemArray.go @@ -0,0 +1,27 @@ +package jsonutil + +import ( + "fmt" +) + +// ItemOrItemArray is a custom type that can hold either a single value of type T or an array of values of type T. +type ItemOrItemArray[T any] []T + +func (t *ItemOrItemArray[T]) UnmarshalJSON(b []byte) error { + // try to unmarshal as a single value of type T first + var itemResult T + if err := UnmarshalValid(b, &itemResult); err == nil { + *t = []T{itemResult} + return nil + } + + // then try to unmarshal as an array of type T + var arrayResult []T + if err := UnmarshalValid(b, &arrayResult); err == nil { + *t = arrayResult + return nil + } + + // if both attempts fail, return an error + return fmt.Errorf("value should be of type %T or %T", itemResult, arrayResult) +} diff --git a/util/jsonutil/itemOrItemArray_test.go b/util/jsonutil/itemOrItemArray_test.go new file mode 100644 index 00000000000..f9ba2fa7d82 --- /dev/null +++ b/util/jsonutil/itemOrItemArray_test.go @@ -0,0 +1,83 @@ +package jsonutil + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestItemOrItemArrayUnmarshalJSON_String(t *testing.T) { + type Data struct { + Item ItemOrItemArray[string] `json:"item"` + } + + t.Run("string", func(t *testing.T) { + jsonData := []byte(`{"item":"hello"}`) + var data Data + assert.NoError(t, UnmarshalValid(jsonData, &data)) + assert.Equal(t, 1, len(data.Item)) + assert.Equal(t, "hello", data.Item[0]) + }) + + t.Run("string_array", func(t *testing.T) { + jsonData := []byte(`{"item":["hello","world"]}`) + var data Data + assert.NoError(t, UnmarshalValid(jsonData, &data)) + assert.Equal(t, 2, len(data.Item)) + assert.Equal(t, "hello", data.Item[0]) + assert.Equal(t, "world", data.Item[1]) + }) + + t.Run("empty_array", func(t *testing.T) { + jsonData := []byte(`{"item": []}`) + var data Data + assert.NoError(t, UnmarshalValid(jsonData, &data)) + assert.Empty(t, data.Item) + }) + + t.Run("invalid_input", func(t *testing.T) { + jsonData := []byte(`{"item":true}`) + var item Data + err := UnmarshalValid(jsonData, &item) + assert.EqualError(t, err, "cannot unmarshal jsonutil.Data.Item: value should be of type string or []string") + }) +} + +func TestItemOrItemArrayUnmarshallJSON_Struct(t *testing.T) { + type Item struct { + Name string `json:"name"` + } + + type Data struct { + Item ItemOrItemArray[Item] `json:"item"` + } + + t.Run("struct", func(t *testing.T) { + jsonData := []byte(`{"item":{"name":"test"}}`) + var data Data + assert.NoError(t, UnmarshalValid(jsonData, &data)) + assert.Equal(t, "test", data.Item[0].Name) + }) + + t.Run("struct_array", func(t *testing.T) { + jsonData := []byte(`{"item":[{"name":"test1"},{"name":"test2"}]}`) + var data Data + assert.NoError(t, UnmarshalValid(jsonData, &data)) + assert.Equal(t, "test1", data.Item[0].Name) + assert.Equal(t, "test2", data.Item[1].Name) + }) + + t.Run("empty_array", func(t *testing.T) { + jsonData := []byte(`{"item":[]}`) + var data Data + assert.NoError(t, UnmarshalValid(jsonData, &data)) + assert.Empty(t, data.Item) + }) + + t.Run("invalid_input", func(t *testing.T) { + jsonData := []byte(`{"item":true}`) + var item Data + err := UnmarshalValid(jsonData, &item) + assert.EqualError(t, err, "cannot unmarshal jsonutil.Data.Item: value should be of type jsonutil.Item or []jsonutil.Item") + }) +} diff --git a/util/jsonutil/stringOrStringArray.go b/util/jsonutil/stringOrStringArray.go deleted file mode 100644 index 322522d31e3..00000000000 --- a/util/jsonutil/stringOrStringArray.go +++ /dev/null @@ -1,27 +0,0 @@ -package jsonutil - -import ( - "errors" -) - -type StringOrStringArray []string - -// parse string or string array input into string array -func (t *StringOrStringArray) UnmarshalJSON(b []byte) error { - // try to unmarshal as a single string first - var stringResult string - if err := UnmarshalValid(b, &stringResult); err == nil { - *t = []string{stringResult} - return nil - } - - // then try to unmarshal as an array of strings - var arrayResult []string - if err := UnmarshalValid(b, &arrayResult); err == nil { - *t = arrayResult - return nil - } - - // if both attempts fail, return an error - return errors.New("value should be of type string or []string") -} diff --git a/util/jsonutil/stringOrStringArray_test.go b/util/jsonutil/stringOrStringArray_test.go deleted file mode 100644 index a88c195d4c5..00000000000 --- a/util/jsonutil/stringOrStringArray_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package jsonutil - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestStringOrStringArrayUnmarshalJSON(t *testing.T) { - type Item struct { - Item StringOrStringArray `json:"item"` - } - - t.Run("string", func(t *testing.T) { - jsonData := []byte(`{"item":"hello"}`) - var item Item - assert.NoError(t, UnmarshalValid(jsonData, &item)) - assert.Equal(t, "hello", item.Item[0]) - }) - - t.Run("string_array", func(t *testing.T) { - jsonData := []byte(`{"item":["hello","world"]}`) - var item Item - assert.NoError(t, UnmarshalValid(jsonData, &item)) - assert.Equal(t, "hello", item.Item[0]) - assert.Equal(t, "world", item.Item[1]) - }) - - t.Run("empty_array", func(t *testing.T) { - jsonData := []byte(`{"item": []}`) - var item Item - assert.NoError(t, UnmarshalValid(jsonData, &item)) - assert.Empty(t, item.Item) - }) - - t.Run("invalid_input", func(t *testing.T) { - jsonData := []byte(`{"item":true}`) - var item Item - err := UnmarshalValid(jsonData, &item) - assert.EqualError(t, err, "cannot unmarshal jsonutil.Item.Item: value should be of type string or []string") - }) -} From 366449abf2633c6008d93aabea6dd989570c1ea2 Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Thu, 9 Oct 2025 14:43:39 +0200 Subject: [PATCH 5/7] use correct error types & remove custom type from jsonutil package again --- adapters/goldbach/goldbach.go | 33 ++++---- adapters/goldbach/goldbach_test.go | 9 +- .../supplemental/invalid-bid-ext.json | 4 +- .../supplemental/invalid-bidder-ext.json | 4 +- .../supplemental/no-bidder-response.json | 4 +- openrtb_ext/imp_goldbach.go | 30 ++++++- static/bidder-info/goldbach.yaml | 1 + util/jsonutil/itemOrItemArray.go | 27 ------ util/jsonutil/itemOrItemArray_test.go | 83 ------------------- 9 files changed, 56 insertions(+), 139 deletions(-) delete mode 100644 util/jsonutil/itemOrItemArray.go delete mode 100644 util/jsonutil/itemOrItemArray_test.go diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go index 48e62f42034..c07b75969c5 100644 --- a/adapters/goldbach/goldbach.go +++ b/adapters/goldbach/goldbach.go @@ -20,7 +20,7 @@ type adapter struct { type requestExtAdapter struct { Goldbach requestExtGoldbach `json:"goldbach"` - *openrtb_ext.ExtRequest `json:",inline,omitempty"` + *openrtb_ext.ExtRequest `json:"inline,omitempty"` } type requestExtGoldbach struct { @@ -33,8 +33,8 @@ type impExtAdapter struct { } type impExtGoldbachOutgoing struct { - Targetings map[string]jsonutil.ItemOrItemArray[string] `json:"targetings,omitempty"` - SlotID string `json:"slotId"` + Targetings map[string][]string `json:"targetings,omitempty"` + SlotID string `json:"slotId"` } func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { @@ -55,7 +55,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E var requestExt requestExtAdapter if request.Ext != nil { if err := jsonutil.Unmarshal(request.Ext, &requestExt); err != nil { - errs = append(errs, fmt.Errorf("unable to unmarshal request.ext: %v", err)) + errs = append(errs, &errortypes.FailedToUnmarshal{Message: fmt.Errorf("unable to unmarshal request.ext: %w", err).Error()}) } } @@ -72,7 +72,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E } if len(publisherImps) == 0 { - errs = append(errs, errors.New("no publisher ID found in impressions")) + errs = append(errs, &errortypes.BadInput{Message: "no publisher ID found in impressions"}) } // create a separate request for each publisher @@ -85,7 +85,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E resJSON, err := jsonutil.Marshal(&requestPublisher) if err != nil { - errs = append(errs, fmt.Errorf("unable to marshal request: %v", err)) + errs = append(errs, &errortypes.FailedToMarshal{Message: fmt.Errorf("unable to marshal request: %w", err).Error()}) continue } @@ -121,7 +121,7 @@ func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, unused *adapters.Request var resp openrtb2.BidResponse if err := jsonutil.Unmarshal(httpRes.Body, &resp); err != nil { return nil, []error{&errortypes.BadServerResponse{ - Message: fmt.Sprintf("unable to unmarshal response: %s", err), + Message: fmt.Errorf("unable to unmarshal response: %w", err).Error(), }} } @@ -160,15 +160,20 @@ func buildImp(imp openrtb2.Imp) (string, openrtb2.Imp, error) { return "", openrtb2.Imp{}, err } + targetings := make(map[string][]string) + for key, value := range impExt.CustomTargeting { + targetings[key] = value + } + imp.Ext, err = jsonutil.Marshal(&impExtAdapter{ Goldbach: impExtGoldbachOutgoing{ - Targetings: impExt.CustomTargeting, + Targetings: targetings, SlotID: impExt.SlotID, }, }) if err != nil { - return "", openrtb2.Imp{}, fmt.Errorf("unable to marshal imp.ext: %v", err) + return "", openrtb2.Imp{}, &errortypes.FailedToMarshal{Message: fmt.Errorf("unable to marshal imp.ext: %w", err).Error()} } return impExt.PublisherID, imp, nil @@ -178,14 +183,14 @@ func extractImpExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtGoldbach, error) { var extImpBidder adapters.ExtImpBidder if err := jsonutil.Unmarshal(imp.Ext, &extImpBidder); err != nil { return nil, &errortypes.BadInput{ - Message: "unable to unmarshal imp.ext", + Message: fmt.Errorf("unable to unmarshal imp.ext: %w", err).Error(), } } var goldbachExt openrtb_ext.ImpExtGoldbach if err := jsonutil.Unmarshal(extImpBidder.Bidder, &goldbachExt); err != nil { return nil, &errortypes.BadInput{ - Message: "unable to unmarshal imp.ext.bidder", + Message: fmt.Errorf("unable to unmarshal imp.ext.bidder: %w", err).Error(), } } @@ -210,7 +215,7 @@ func buildRequest(request openrtb2.BidRequest, publisherID string, imps *[]openr ExtRequest: requestExt.ExtRequest, }) if err != nil { - return nil, fmt.Errorf("unable to marshal request.ext: %v", err) + return nil, &errortypes.FailedToMarshal{Message: fmt.Errorf("unable to marshal request.ext: %w", err).Error()} } request.Ext = requestPublisherExt @@ -221,11 +226,11 @@ func buildRequest(request openrtb2.BidRequest, publisherID string, imps *[]openr func getBidMediaType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { var extBid openrtb_ext.ExtBid if err := jsonutil.Unmarshal(bid.Ext, &extBid); err != nil { - return "", fmt.Errorf("unable to unmarshal ext for bid %v", bid.ID) + return "", &errortypes.FailedToUnmarshal{Message: fmt.Errorf("unable to unmarshal ext for bid: %w", err).Error()} } if extBid.Prebid == nil || len(extBid.Prebid.Type) == 0 { - return "", fmt.Errorf("no media type for bid %v", bid.ID) + return "", &errortypes.BadInput{Message: fmt.Sprintf("no media type for bid %v", bid.ID)} } return extBid.Prebid.Type, nil diff --git a/adapters/goldbach/goldbach_test.go b/adapters/goldbach/goldbach_test.go index d8a12efc4c6..740b1d11bf9 100644 --- a/adapters/goldbach/goldbach_test.go +++ b/adapters/goldbach/goldbach_test.go @@ -6,6 +6,7 @@ import ( "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/require" ) func TestJsonSamples(t *testing.T) { @@ -15,9 +16,7 @@ func TestJsonSamples(t *testing.T) { config.Server{}, ) - if buildErr == nil { - t.Fatalf("Builder should have returned error") - } + require.Error(t, buildErr) bidder, buildErr := Builder( openrtb_ext.BidderGoldbach, @@ -31,9 +30,7 @@ func TestJsonSamples(t *testing.T) { }, ) - if buildErr != nil { - t.Fatalf("Builder returned unexpected error %v", buildErr) - } + require.NoError(t, buildErr) adapterstest.RunJSONBidderTest(t, "goldbachtest", bidder) } diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json index fce52d31c84..48f18a454b1 100644 --- a/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json @@ -22,8 +22,8 @@ "httpCalls": [], "expectedMakeRequestsErrors": [ { - "value": "unable to unmarshal imp.ext", - "comparison": "literal" + "value": "^unable to unmarshal imp.ext:", + "comparison": "regex" }, { "value": "no publisher ID found in impressions", diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json index 681f7242ae7..d8124c0eca1 100644 --- a/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json @@ -24,8 +24,8 @@ "httpCalls": [], "expectedMakeRequestsErrors": [ { - "value": "unable to unmarshal imp.ext.bidder", - "comparison": "literal" + "value": "^unable to unmarshal imp.ext.bidder:", + "comparison": "regex" }, { "value": "no publisher ID found in impressions", diff --git a/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json b/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json index a88f7279771..b045343fa61 100644 --- a/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json +++ b/adapters/goldbach/goldbachtest/supplemental/no-bidder-response.json @@ -97,8 +97,8 @@ ], "expectedMakeBidsErrors": [ { - "value": "unable to unmarshal ext for bid test-bid-123", - "comparison": "literal" + "value": "^unable to unmarshal ext for bid:", + "comparison": "regex" }, { "value": "no valid bids found in response", diff --git a/openrtb_ext/imp_goldbach.go b/openrtb_ext/imp_goldbach.go index 6c005bcb910..238ef2ff2e5 100644 --- a/openrtb_ext/imp_goldbach.go +++ b/openrtb_ext/imp_goldbach.go @@ -1,11 +1,35 @@ package openrtb_ext import ( + "fmt" + "github.com/prebid/prebid-server/v3/util/jsonutil" ) type ImpExtGoldbach struct { - PublisherID string `json:"publisherId"` - SlotID string `json:"slotId"` - CustomTargeting map[string]jsonutil.ItemOrItemArray[string] `json:"customTargeting,omitempty"` + PublisherID string `json:"publisherId"` + SlotID string `json:"slotId"` + CustomTargeting map[string]stringOrStringArray `json:"customTargeting,omitempty"` +} + +// stringOrStringArray is a custom type that can hold either a single value of type T or an array of values of type T. +type stringOrStringArray []string + +func (t *stringOrStringArray) UnmarshalJSON(b []byte) error { + // try to unmarshal as a single value of type T first + var itemResult string + if err := jsonutil.UnmarshalValid(b, &itemResult); err == nil { + *t = []string{itemResult} + return nil + } + + // then try to unmarshal as an array of type T + var arrayResult []string + if err := jsonutil.UnmarshalValid(b, &arrayResult); err == nil { + *t = arrayResult + return nil + } + + // if both attempts fail, return an error + return fmt.Errorf("value should be of type %T or %T", itemResult, arrayResult) } diff --git a/static/bidder-info/goldbach.yaml b/static/bidder-info/goldbach.yaml index 2b8b57393ee..2644e83853e 100644 --- a/static/bidder-info/goldbach.yaml +++ b/static/bidder-info/goldbach.yaml @@ -1,4 +1,5 @@ endpoint: "https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction" +endpointCompression: true maintainer: email: "engineering@goldbach.com" gvlVendorID: 580 diff --git a/util/jsonutil/itemOrItemArray.go b/util/jsonutil/itemOrItemArray.go deleted file mode 100644 index 854bd67a8be..00000000000 --- a/util/jsonutil/itemOrItemArray.go +++ /dev/null @@ -1,27 +0,0 @@ -package jsonutil - -import ( - "fmt" -) - -// ItemOrItemArray is a custom type that can hold either a single value of type T or an array of values of type T. -type ItemOrItemArray[T any] []T - -func (t *ItemOrItemArray[T]) UnmarshalJSON(b []byte) error { - // try to unmarshal as a single value of type T first - var itemResult T - if err := UnmarshalValid(b, &itemResult); err == nil { - *t = []T{itemResult} - return nil - } - - // then try to unmarshal as an array of type T - var arrayResult []T - if err := UnmarshalValid(b, &arrayResult); err == nil { - *t = arrayResult - return nil - } - - // if both attempts fail, return an error - return fmt.Errorf("value should be of type %T or %T", itemResult, arrayResult) -} diff --git a/util/jsonutil/itemOrItemArray_test.go b/util/jsonutil/itemOrItemArray_test.go deleted file mode 100644 index f9ba2fa7d82..00000000000 --- a/util/jsonutil/itemOrItemArray_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package jsonutil - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestItemOrItemArrayUnmarshalJSON_String(t *testing.T) { - type Data struct { - Item ItemOrItemArray[string] `json:"item"` - } - - t.Run("string", func(t *testing.T) { - jsonData := []byte(`{"item":"hello"}`) - var data Data - assert.NoError(t, UnmarshalValid(jsonData, &data)) - assert.Equal(t, 1, len(data.Item)) - assert.Equal(t, "hello", data.Item[0]) - }) - - t.Run("string_array", func(t *testing.T) { - jsonData := []byte(`{"item":["hello","world"]}`) - var data Data - assert.NoError(t, UnmarshalValid(jsonData, &data)) - assert.Equal(t, 2, len(data.Item)) - assert.Equal(t, "hello", data.Item[0]) - assert.Equal(t, "world", data.Item[1]) - }) - - t.Run("empty_array", func(t *testing.T) { - jsonData := []byte(`{"item": []}`) - var data Data - assert.NoError(t, UnmarshalValid(jsonData, &data)) - assert.Empty(t, data.Item) - }) - - t.Run("invalid_input", func(t *testing.T) { - jsonData := []byte(`{"item":true}`) - var item Data - err := UnmarshalValid(jsonData, &item) - assert.EqualError(t, err, "cannot unmarshal jsonutil.Data.Item: value should be of type string or []string") - }) -} - -func TestItemOrItemArrayUnmarshallJSON_Struct(t *testing.T) { - type Item struct { - Name string `json:"name"` - } - - type Data struct { - Item ItemOrItemArray[Item] `json:"item"` - } - - t.Run("struct", func(t *testing.T) { - jsonData := []byte(`{"item":{"name":"test"}}`) - var data Data - assert.NoError(t, UnmarshalValid(jsonData, &data)) - assert.Equal(t, "test", data.Item[0].Name) - }) - - t.Run("struct_array", func(t *testing.T) { - jsonData := []byte(`{"item":[{"name":"test1"},{"name":"test2"}]}`) - var data Data - assert.NoError(t, UnmarshalValid(jsonData, &data)) - assert.Equal(t, "test1", data.Item[0].Name) - assert.Equal(t, "test2", data.Item[1].Name) - }) - - t.Run("empty_array", func(t *testing.T) { - jsonData := []byte(`{"item":[]}`) - var data Data - assert.NoError(t, UnmarshalValid(jsonData, &data)) - assert.Empty(t, data.Item) - }) - - t.Run("invalid_input", func(t *testing.T) { - jsonData := []byte(`{"item":true}`) - var item Data - err := UnmarshalValid(jsonData, &item) - assert.EqualError(t, err, "cannot unmarshal jsonutil.Data.Item: value should be of type jsonutil.Item or []jsonutil.Item") - }) -} From e9d4ed4939edde518a81fd80d051c4132e01b08f Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Fri, 10 Oct 2025 13:12:40 +0200 Subject: [PATCH 6/7] reword error message --- adapters/goldbach/goldbach.go | 2 +- .../goldbach/goldbachtest/supplemental/empty-publisher-id.json | 2 +- adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json | 2 +- .../goldbach/goldbachtest/supplemental/invalid-bid-ext.json | 2 +- .../goldbach/goldbachtest/supplemental/invalid-bidder-ext.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go index c07b75969c5..b1de1f1da2b 100644 --- a/adapters/goldbach/goldbach.go +++ b/adapters/goldbach/goldbach.go @@ -72,7 +72,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E } if len(publisherImps) == 0 { - errs = append(errs, &errortypes.BadInput{Message: "no publisher ID found in impressions"}) + errs = append(errs, &errortypes.BadInput{Message: "no valid impression found"}) } // create a separate request for each publisher diff --git a/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json b/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json index 4f0f3c71295..f034a246522 100644 --- a/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json +++ b/adapters/goldbach/goldbachtest/supplemental/empty-publisher-id.json @@ -31,7 +31,7 @@ "comparison": "literal" }, { - "value": "no publisher ID found in impressions", + "value": "no valid impression found", "comparison": "literal" } ] diff --git a/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json b/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json index f9c3cfd2083..05ffb09d63c 100644 --- a/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json +++ b/adapters/goldbach/goldbachtest/supplemental/empty-slot-id.json @@ -31,7 +31,7 @@ "comparison": "literal" }, { - "value": "no publisher ID found in impressions", + "value": "no valid impression found", "comparison": "literal" } ] diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json index 48f18a454b1..e23fab66143 100644 --- a/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bid-ext.json @@ -26,7 +26,7 @@ "comparison": "regex" }, { - "value": "no publisher ID found in impressions", + "value": "no valid impression found", "comparison": "literal" } ] diff --git a/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json index d8124c0eca1..ac704eb4222 100644 --- a/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json +++ b/adapters/goldbach/goldbachtest/supplemental/invalid-bidder-ext.json @@ -28,7 +28,7 @@ "comparison": "regex" }, { - "value": "no publisher ID found in impressions", + "value": "no valid impression found", "comparison": "literal" } ] From 4a9af4720b75430c1cb8ee348a9859c57f059429 Mon Sep 17 00:00:00 2001 From: Simon Aebli Date: Thu, 16 Oct 2025 09:30:06 +0200 Subject: [PATCH 7/7] error handling during testing & cleanup --- adapters/goldbach/goldbach.go | 11 +++-------- adapters/goldbach/goldbach_test.go | 8 -------- adapters/goldbach/params_test.go | 20 ++++++++------------ static/bidder-info/goldbach.yaml | 2 +- 4 files changed, 12 insertions(+), 29 deletions(-) diff --git a/adapters/goldbach/goldbach.go b/adapters/goldbach/goldbach.go index b1de1f1da2b..5c500e63cea 100644 --- a/adapters/goldbach/goldbach.go +++ b/adapters/goldbach/goldbach.go @@ -1,7 +1,6 @@ package goldbach import ( - "errors" "fmt" "net/http" @@ -38,10 +37,6 @@ type impExtGoldbachOutgoing struct { } func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { - if config.Endpoint == "" { - return nil, errors.New("missing endpoint adapter parameter") - } - bidder := &adapter{ endpoint: config.Endpoint, } @@ -77,7 +72,7 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.E // create a separate request for each publisher for publisherID, imps := range publisherImps { - requestPublisher, err := buildRequest(*request, publisherID, &imps, &requestExt) + requestPublisher, err := buildRequest(*request, publisherID, imps, &requestExt) if err != nil { errs = append(errs, err) continue @@ -202,8 +197,8 @@ func extractImpExt(imp *openrtb2.Imp) (*openrtb_ext.ImpExtGoldbach, error) { return &goldbachExt, nil } -func buildRequest(request openrtb2.BidRequest, publisherID string, imps *[]openrtb2.Imp, requestExt *requestExtAdapter) (*openrtb2.BidRequest, error) { - request.Imp = *imps +func buildRequest(request openrtb2.BidRequest, publisherID string, imps []openrtb2.Imp, requestExt *requestExtAdapter) (*openrtb2.BidRequest, error) { + request.Imp = imps request.ID = fmt.Sprintf("%s_%s", request.ID, publisherID) // Set the publisher ID in the request.ext diff --git a/adapters/goldbach/goldbach_test.go b/adapters/goldbach/goldbach_test.go index 740b1d11bf9..a1f046adfe4 100644 --- a/adapters/goldbach/goldbach_test.go +++ b/adapters/goldbach/goldbach_test.go @@ -10,14 +10,6 @@ import ( ) func TestJsonSamples(t *testing.T) { - _, buildErr := Builder( - openrtb_ext.BidderGoldbach, - config.Adapter{}, - config.Server{}, - ) - - require.Error(t, buildErr) - bidder, buildErr := Builder( openrtb_ext.BidderGoldbach, config.Adapter{ diff --git a/adapters/goldbach/params_test.go b/adapters/goldbach/params_test.go index 502b2cd5deb..b03d182247e 100644 --- a/adapters/goldbach/params_test.go +++ b/adapters/goldbach/params_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/stretchr/testify/require" ) // This file actually intends to test static/bidder-params/goldbach.json @@ -13,28 +14,23 @@ import ( func TestValidParams(t *testing.T) { validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") - if err != nil { - t.Fatalf("Failed to fetch the json-schemas. %v", err) - } + require.NoError(t, err, "Failed to fetch the json-schemas. %v", err) for _, validParam := range validParams { - if err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(validParam)); err != nil { - t.Errorf("Schema rejected goldbach params: %s", validParam) - } + err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(validParam)) + + require.NoError(t, err, "Schema rejected goldbach params: %s", validParam) } } // TestInvalidParams makes sure that the goldbach schema rejects all the imp.ext fields we don't support. func TestInvalidParams(t *testing.T) { validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") - if err != nil { - t.Fatalf("Failed to fetch the json-schemas. %v", err) - } + require.NoError(t, err, "Failed to fetch the json-schemas. %v", err) for _, invalidParam := range invalidParams { - if err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(invalidParam)); err == nil { - t.Errorf("Schema allowed unexpected params: %s", invalidParam) - } + err := validator.Validate(openrtb_ext.BidderGoldbach, json.RawMessage(invalidParam)) + require.Error(t, err, "Schema allowed unexpected params: %s", invalidParam) } } diff --git a/static/bidder-info/goldbach.yaml b/static/bidder-info/goldbach.yaml index 2644e83853e..08d43ba216e 100644 --- a/static/bidder-info/goldbach.yaml +++ b/static/bidder-info/goldbach.yaml @@ -1,5 +1,5 @@ endpoint: "https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction" -endpointCompression: true +endpointCompression: gzip maintainer: email: "engineering@goldbach.com" gvlVendorID: 580