-
Notifications
You must be signed in to change notification settings - Fork 928
New Adapter: Synapse HX #4795
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New Adapter: Synapse HX #4795
Changes from all commits
0d9643b
0a22422
48994af
2033b28
f70eabf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| 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) { | ||
| 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":""}`, | ||
| } | ||
| 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)) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. or depending on what makes sense for you.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add supplemental JSON tests to cover these cases.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add a supplemental JSON test to cover this line.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
| } | ||
| 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) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| } | ||
| 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" | ||
| } | ||
| ] | ||
| } | ||
| ] | ||
| } |


There was a problem hiding this comment.
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:
The reported 76.9% coverage on getMediaTypeForBid confirms these gaps.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests were added.