Skip to content

Commit

Permalink
New adapter: Xeworks (#2752)
Browse files Browse the repository at this point in the history
  • Loading branch information
dimashirokov committed May 29, 2023
1 parent f2add44 commit f390f79
Show file tree
Hide file tree
Showing 22 changed files with 2,072 additions and 0 deletions.
53 changes: 53 additions & 0 deletions adapters/xeworks/params_test.go
@@ -0,0 +1,53 @@
package xeworks

import (
"encoding/json"
"testing"

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

var validParams = []string{
`{"env":"xe-stage", "pid":"123456"}`,
}

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.BidderXeworks, json.RawMessage(validParam)); err != nil {
t.Errorf("Schema rejected xeworks params: %s", validParam)
}
}
}

var invalidParams = []string{
``,
`null`,
`true`,
`5`,
`[]`,
`{}`,
`{"some": "param"}`,
`{"env":"xe-stage"}`,
`{"pid":"1234"}`,
`{"othervalue":"Lorem ipsum"}`,
`{"env":"xe-stage", pid:""}`,
`{"env":"", pid:"1234"}`,
}

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.BidderXeworks, json.RawMessage(invalidParam)); err == nil {
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
}
}
}
162 changes: 162 additions & 0 deletions adapters/xeworks/xeworks.go
@@ -0,0 +1,162 @@
package xeworks

import (
"encoding/json"
"fmt"
"net/http"
"text/template"

"github.com/prebid/openrtb/v19/openrtb2"
"github.com/prebid/prebid-server/adapters"
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/errortypes"
"github.com/prebid/prebid-server/macros"
"github.com/prebid/prebid-server/openrtb_ext"
"github.com/prebid/prebid-server/util/httputil"
)

type bidType struct {
Type string `json:"type"`
}

type bidExt struct {
Prebid bidType `json:"prebid"`
}

type adapter struct {
endpoint *template.Template
}

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
tmpl, err := template.New("endpointTemplate").Parse(config.Endpoint)
if err != nil {
return nil, fmt.Errorf("unable to parse endpoint URL template: %v", err)
}

bidder := &adapter{
endpoint: tmpl,
}

return bidder, nil
}

func (a *adapter) buildEndpointFromRequest(imp *openrtb2.Imp) (string, error) {
var impExt adapters.ExtImpBidder
if err := json.Unmarshal(imp.Ext, &impExt); err != nil {
return "", &errortypes.BadInput{
Message: fmt.Sprintf("Failed to deserialize bidder impression extension: %v", err),
}
}

var xeworksExt openrtb_ext.ExtXeworks
if err := json.Unmarshal(impExt.Bidder, &xeworksExt); err != nil {
return "", &errortypes.BadInput{
Message: fmt.Sprintf("Failed to deserialize Xeworks extension: %v", err),
}
}

endpointParams := macros.EndpointTemplateParams{
Host: xeworksExt.Env,
SourceId: xeworksExt.Pid,
}

return macros.ResolveMacros(a.endpoint, endpointParams)
}

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

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

requestCopy := *request
for _, imp := range request.Imp {
requestCopy.Imp = []openrtb2.Imp{imp}

endpoint, err := a.buildEndpointFromRequest(&imp)
if err != nil {
errs = append(errs, err)
continue
}

requestJSON, err := json.Marshal(requestCopy)
if err != nil {
errs = append(errs, err)
continue
}

request := &adapters.RequestData{
Method: http.MethodPost,
Body: requestJSON,
Uri: endpoint,
Headers: headers,
}

requests = append(requests, request)
}

return requests, errs
}

func (a *adapter) MakeBids(openRTBRequest *openrtb2.BidRequest, requestToBidder *adapters.RequestData, bidderRawResponse *adapters.ResponseData) (*adapters.BidderResponse, []error) {
if httputil.IsResponseStatusCodeNoContent(bidderRawResponse) {

Check failure on line 104 in adapters/xeworks/xeworks.go

View workflow job for this annotation

GitHub Actions / validate (1.18.x, ubuntu-20.04)

undefined: httputil.IsResponseStatusCodeNoContent

Check failure on line 104 in adapters/xeworks/xeworks.go

View workflow job for this annotation

GitHub Actions / validate (1.19.x, ubuntu-20.04)

undefined: httputil.IsResponseStatusCodeNoContent
return nil, nil
}

if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
return nil, []error{&errortypes.BadInput{
Message: "Bidder Xeworks is unavailable. Please contact the bidder support.",
}}
}

if err := httputil.CheckResponseStatusCodeForErrors(bidderRawResponse); err != nil {

Check failure on line 114 in adapters/xeworks/xeworks.go

View workflow job for this annotation

GitHub Actions / validate (1.18.x, ubuntu-20.04)

undefined: httputil.CheckResponseStatusCodeForErrors

Check failure on line 114 in adapters/xeworks/xeworks.go

View workflow job for this annotation

GitHub Actions / validate (1.19.x, ubuntu-20.04)

undefined: httputil.CheckResponseStatusCodeForErrors
return nil, []error{err}
}

var bidResp openrtb2.BidResponse
if err := json.Unmarshal(bidderRawResponse.Body, &bidResp); err != nil {
return nil, []error{err}
}

if len(bidResp.SeatBid) == 0 {
return nil, []error{&errortypes.BadServerResponse{
Message: "Array SeatBid cannot be empty",
}}
}

return prepareBidResponse(bidResp.SeatBid)
}

func prepareBidResponse(seats []openrtb2.SeatBid) (*adapters.BidderResponse, []error) {
errs := []error{}
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(seats))

for _, seatBid := range seats {
for bidId, bid := range seatBid.Bid {
var bidExt bidExt
if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
errs = append(errs, &errortypes.BadServerResponse{
Message: fmt.Sprintf("Failed to parse Bid[%d].Ext: %s", bidId, err.Error()),
})
continue
}

bidType, err := openrtb_ext.ParseBidType(bidExt.Prebid.Type)
if err != nil {
errs = append(errs, &errortypes.BadServerResponse{
Message: fmt.Sprintf("Bid[%d].Ext.Prebid.Type expects one of the following values: 'banner', 'native', 'video', 'audio', got '%s'", bidId, bidExt.Prebid.Type),
})
continue
}

bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &seatBid.Bid[bidId],
BidType: bidType,
})
}
}

return bidResponse, errs
}
27 changes: 27 additions & 0 deletions adapters/xeworks/xeworks_test.go
@@ -0,0 +1,27 @@
package xeworks

import (
"testing"

"github.com/prebid/prebid-server/adapters/adapterstest"
"github.com/prebid/prebid-server/config"
"github.com/prebid/prebid-server/openrtb_ext"
"github.com/stretchr/testify/assert"
)

func TestJsonSamples(t *testing.T) {
bidder, buildErr := Builder(
openrtb_ext.BidderSmartHub,
config.Adapter{
Endpoint: "http://prebid-srv.xe.works/?pid={{.SourceId}}&host={{.Host}}",
},
config.Server{
ExternalUrl: "http://hosturl.com",
GvlID: 1,
DataCenter: "2",
},
)

assert.NoError(t, buildErr)
adapterstest.RunJSONBidderTest(t, "xeworkstest", bidder)
}

0 comments on commit f390f79

Please sign in to comment.