Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
45 changes: 45 additions & 0 deletions adapters/synapseHX/params_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package synapseHX

import (
"encoding/json"
"testing"

"github.com/prebid/prebid-server/v4/openrtb_ext"
)

func TestValidParams(t *testing.T) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As flagged by @bsardo, tests are missing for:

  • Empty seatbid array in response
  • request.Imp is empty
  • Unmarshal failure on impression ext
  • getMediaTypeForBid with no mtype and no bid.ext

The reported 76.9% coverage on getMediaTypeForBid confirms these gaps.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests were added.

validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
if err != nil {
t.Fatalf("Failed to fetch json-schemas. %v", err)
}

for _, param := range validParams {
if err := validator.Validate(openrtb_ext.BidderSynapseHX, json.RawMessage(param)); err != nil {
t.Errorf("Schema rejected valid params: %s", param)
}
}
}

func TestInvalidParams(t *testing.T) {
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
if err != nil {
t.Fatalf("Failed to fetch json-schemas. %v", err)
}

for _, param := range invalidParams {
if err := validator.Validate(openrtb_ext.BidderSynapseHX, json.RawMessage(param)); err == nil {
t.Errorf("Schema allowed invalid params: %s", param)
}
}
}

var validParams = []string{
`{"tenantId":"a"}`,
`{"tenantId":"8cd85aed-25a6-4db0-ad98-4a3af1f7601c"}`,
}

var invalidParams = []string{
`{}`,
`{"tenantId":1}`,
`{"tenantId":""}`,
}
147 changes: 147 additions & 0 deletions adapters/synapseHX/synapseHX.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package synapseHX

import (
"fmt"
"net/http"
"net/url"

"github.com/prebid/openrtb/v20/openrtb2"
"github.com/prebid/prebid-server/v4/adapters"
"github.com/prebid/prebid-server/v4/config"
"github.com/prebid/prebid-server/v4/errortypes"
"github.com/prebid/prebid-server/v4/openrtb_ext"
"github.com/prebid/prebid-server/v4/util/jsonutil"
)

type adapter struct {
endpoint string
}

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
bidder := &adapter{
endpoint: config.Endpoint,
}

return bidder, nil
}

func (adapter *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
var requests []*adapters.RequestData

var tenantId string

if len(request.Imp) == 0 {
return nil, []error{fmt.Errorf("request contains no impressions")}
}

var bidderExt adapters.ExtImpBidder
if err := jsonutil.Unmarshal(request.Imp[0].Ext, &bidderExt); err != nil {
return nil, []error{fmt.Errorf("failed to unmarshal bidder ext: %w", err)}
}

var ext openrtb_ext.ExtImpSynapseHX
if err := jsonutil.Unmarshal(bidderExt.Bidder, &ext); err != nil {
return nil, []error{fmt.Errorf("failed to unmarshal bidder parameters: %w", err)}
}

tenantId = ext.TenantID

requestBody, err := jsonutil.Marshal(request)
if err != nil {
return nil, []error{fmt.Errorf("failed to marshal request: %w", err)}
}

url, _ := url.Parse(adapter.endpoint)
q := url.Query()
q.Set("pid", tenantId)
url.RawQuery = q.Encode()

requestData := &adapters.RequestData{
Method: http.MethodPost,
Uri: url.String(),
Body: requestBody,
Headers: buildRequestHeaders(),
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
}

requests = append(requests, requestData)

return requests, nil
}

func (adapter *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if adapters.IsResponseStatusCodeNoContent(response) {
return nil, nil
}

if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
return nil, []error{err}
}

var bidResponse openrtb2.BidResponse
if err := jsonutil.Unmarshal(response.Body, &bidResponse); err != nil {
return nil, []error{&errortypes.BadInput{Message: fmt.Sprintf("failed to unmarshal response body: %v", err)}}
}

if len(bidResponse.SeatBid) == 0 || len(bidResponse.SeatBid[0].Bid) == 0 {
return nil, nil
}

var errs []error
bidderResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResponse.SeatBid[0].Bid))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest ensuring there is at least one seatbid before attempting to access the first element.
Something like:

if len(bidResponse.SeatBid) == 0 {
	return nil, nil
}

or

if len(bidResponse.SeatBid) == 0 {
	return nil, []error{&errortypes.BadServerResponse{
		Message: "Empty SeatBid array",
	}}
}

depending on what makes sense for you.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also cover the new logic I suggested above with a supplemental JSON test.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


for i := range bidResponse.SeatBid {
for j := range bidResponse.SeatBid[i].Bid {
bid := &bidResponse.SeatBid[i].Bid[j]
bidType, err := getMediaTypeForBid(bid)

if err != nil {
errs = append(errs, err)
} else {
bidderResponse.Bids = append(bidderResponse.Bids, &adapters.TypedBid{
Bid: bid,
BidType: bidType,
})
}
}
}

return bidderResponse, errs
}

func buildRequestHeaders() http.Header {
headers := http.Header{}
headers.Add("Content-Type", "application/json;charset=utf-8")
headers.Add("Accept", "application/json")
headers.Add("X-Openrtb-Version", "2.6")

return headers
}

func getMediaTypeForBid(bid *openrtb2.Bid) (openrtb_ext.BidType, error) {
if bid.MType != 0 {
switch bid.MType {
case openrtb2.MarkupBanner:
return openrtb_ext.BidTypeBanner, nil
case openrtb2.MarkupVideo:
return openrtb_ext.BidTypeVideo, nil
default:
return "", fmt.Errorf("unsupported media type %d", bid.MType)
}
Comment on lines +126 to +130

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add supplemental JSON tests to cover these cases.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

if bid.Ext != nil {
var bidExt openrtb_ext.ExtBid
err := jsonutil.Unmarshal(bid.Ext, &bidExt)
if err == nil && bidExt.Prebid != nil {
switch bidExt.Prebid.Type {
case openrtb_ext.BidTypeBanner, openrtb_ext.BidTypeVideo:
return bidExt.Prebid.Type, nil
default:
return "", fmt.Errorf("unsupported media type \"%s\"", bidExt.Prebid.Type)
}
}
}

return "", fmt.Errorf("failed to parse impression \"%s\" mediatype", bid.ImpID)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a supplemental JSON test to cover this line.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
18 changes: 18 additions & 0 deletions adapters/synapseHX/synapseHX_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package synapseHX

import (
"testing"

"github.com/prebid/prebid-server/v4/adapters/adapterstest"
"github.com/prebid/prebid-server/v4/config"
"github.com/prebid/prebid-server/v4/openrtb_ext"
)

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(openrtb_ext.BidderSynapseHX, config.Adapter{
Endpoint: "http://localhost:8080/bidder/"}, config.Server{})
if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
}
adapterstest.RunJSONBidderTest(t, "synapseHXtest", bidder)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The convention in this repo is to pass the adapter directory name (e.g., "synapseHX"), not "synapseHXtest". This may cause the test to silently look in the wrong directory.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.

We checked this across the repository and based on the existing usage examples it does not match with your suggestion - here are a few screenshots from the repo for reference. The same behavior also seems to be aligned with the official documentation here: https://docs.prebid.org/prebid-server/developers/add-new-bidder-go.html#test-your-adapter

Please, let us know your opinion. On our side, we have ready-to-push change to address this.
image
image

}
167 changes: 167 additions & 0 deletions adapters/synapseHX/synapseHXtest/exemplary/banner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
{
"mockBidRequest": {
"id": "auction-req-id",
"imp": [
{
"id": "imp-id",
"ext": {
"bidder": {
"tenantId": "a",
"adUnitId": "b"
}
},
"banner": {
"w": 320,
"h": 480,
"pos": 7,
"mimes": [
"image/jpg",
"image/gif",
"text/html"
],
"format": [
{
"w": 320,
"h": 480
}
],
"api": [
5,
7
],
"vcm": 1,
"id": "1"
}
}
],
"site": {
"page": "https://example.com",
"publisher": {
"id": "publisher-id"
},
"id": "site-id"
},
"device": {
"ua": "Mozilla/5.0"
}
},
"httpCalls": [
{
"expectedRequest": {
"headers": {
"Content-Type": [
"application/json;charset=utf-8"
],
"Accept": [
"application/json"
],
"X-Openrtb-Version": [
"2.6"
]
},
"uri": "http://localhost:8080/bidder/?pid=a",
"body": {
"id": "auction-req-id",
"imp": [
{
"id": "imp-id",
"ext": {
"bidder": {
"tenantId": "a",
"adUnitId": "b"
}
},
"banner": {
"w": 320,
"h": 480,
"pos": 7,
"mimes": [
"image/jpg",
"image/gif",
"text/html"
],
"format": [
{
"w": 320,
"h": 480
}
],
"api": [
5,
7
],
"vcm": 1,
"id": "1"
}
}
],
"site": {
"page": "https://example.com",
"publisher": {
"id": "publisher-id"
},
"id": "site-id"
},
"device": {
"ua": "Mozilla/5.0"
}
},
"impIDs": [
"imp-id"
]
},
"mockResponse": {
"status": 200,
"headers": {
"Content-Type": [
"application/json;charset=utf-8"
],
"X-Openrtb-Version": [
"2.6"
]
},
"body": {
"id": "bid-resp-id",
"seatbid": [
{
"bid": [
{
"id": "bid-item-id",
"impid": "imp-id",
"price": 0.04,
"adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>",
"adomain": [
"example.com"
],
"mtype": 1
}
],
"seat": "seat-1"
}
],
"cur": "USD"
}
}
}
],
"expectedBidResponses": [
{
"id": "bid-resp-id",
"bids": [
{
"bid": {
"id": "bid-item-id",
"impid": "imp-id",
"price": 0.04,
"adm": "<a href='https://advertiser.com/click' target='_blank'><img src='https://advertiser.com/banner.jpg' width='320' height='50' alt='Ad'></a>",
"adomain": [
"example.com"
],
"mtype": 1
},
"type": "banner"
}
]
}
]
}
Loading
Loading