Skip to content

Commit 4239545

Browse files
authored
New Adapter: SuperEdge (prebid#4846)
1 parent 653cc1b commit 4239545

21 files changed

Lines changed: 1627 additions & 0 deletions

‎adapters/superedge/params_test.go‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package superedge
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
7+
"github.com/prebid/prebid-server/v4/openrtb_ext"
8+
)
9+
10+
func TestValidParams(t *testing.T) {
11+
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
12+
if err != nil {
13+
t.Fatalf("Failed to fetch the json-schemas. %v", err)
14+
}
15+
16+
for _, validParam := range validParams {
17+
if err := validator.Validate(openrtb_ext.BidderSuperEdge, json.RawMessage(validParam)); err != nil {
18+
t.Errorf("Schema rejected superEdge params: %s with err: %v", validParam, err)
19+
}
20+
}
21+
}
22+
23+
// TestInvalidParams makes sure that the superEdge schema rejects all the imp.ext fields we don't support.
24+
func TestInvalidParams(t *testing.T) {
25+
validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
26+
if err != nil {
27+
t.Fatalf("Failed to fetch the json-schemas. %v", err)
28+
}
29+
30+
for _, invalidParam := range invalidParams {
31+
if err := validator.Validate(openrtb_ext.BidderSuperEdge, json.RawMessage(invalidParam)); err == nil {
32+
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
33+
}
34+
}
35+
}
36+
37+
var validParams = []string{
38+
`{"sk": "7f096f84f44f4adfa7602f037179c98b"}`,
39+
`{"sk": "1e9ead5397ae44d78c6792bc7cddc050"}`,
40+
`{"sk": "27bb74d57068406ebcbb29ab9bfeb9b9"}`,
41+
`{"sk": "0c3356713c184ca186779eecdd5aff5d"}`,
42+
`{"sk": "f9f2b1ef23fe2759c2cad0953029a94b", "region": "US"}`,
43+
`{"sk": "f9f2b1ef23fe2759c2cad0953029a94b", "region": "EU"}`,
44+
`{"sk": "f9f2b1ef23fe2759c2cad0953029a94b", "region": "APAC"}`,
45+
}
46+
47+
var invalidParams = []string{
48+
`{}`,
49+
`{"tn": "0c3356713c184ca186779eecdd5aff5d"}`,
50+
`{"region": "APAC"}`,
51+
`{"region": "US"}`,
52+
`{"tn": "27bb74d57068406ebcbb29ab9bfeb9b9"}`,
53+
`{"sk": 123}`,
54+
`{"sk": ""}`,
55+
`{"sk": "f9f2b1ef23fe2759c2cad0953029a94b", "region": "JP"}`,
56+
}

‎adapters/superedge/superedge.go‎

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package superedge
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"net/url"
7+
"text/template"
8+
9+
"github.com/prebid/openrtb/v20/openrtb2"
10+
"github.com/prebid/prebid-server/v4/adapters"
11+
"github.com/prebid/prebid-server/v4/config"
12+
"github.com/prebid/prebid-server/v4/errortypes"
13+
"github.com/prebid/prebid-server/v4/macros"
14+
"github.com/prebid/prebid-server/v4/openrtb_ext"
15+
"github.com/prebid/prebid-server/v4/util/jsonutil"
16+
)
17+
18+
type adapter struct {
19+
EndpointTemplate *template.Template
20+
}
21+
22+
// Builder builds a new instance of the SuperEdge adapter for the given bidder with the given config.
23+
func Builder(_ openrtb_ext.BidderName, config config.Adapter, _ config.Server) (adapters.Bidder, error) {
24+
endpoint, err := template.New("").Parse(config.Endpoint)
25+
if err != nil {
26+
return nil, fmt.Errorf("unable to parse endpoint url template: %v", err)
27+
}
28+
bidder := &adapter{EndpointTemplate: endpoint}
29+
return bidder, nil
30+
}
31+
32+
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, _ *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
33+
var adapterRequests []*adapters.RequestData
34+
var errs []error
35+
adapterRequest, err := a.makeRequest(request)
36+
if err == nil {
37+
adapterRequests = append(adapterRequests, adapterRequest)
38+
} else {
39+
errs = append(errs, err)
40+
}
41+
return adapterRequests, errs
42+
}
43+
44+
func (a *adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) {
45+
superEdgeExt, err := getSuperEdgeExt(request)
46+
if err != nil {
47+
return nil, err
48+
}
49+
endPoint, err := a.getEndPoint(superEdgeExt)
50+
if err != nil {
51+
return nil, err
52+
}
53+
requestCopy := *request
54+
requestCopy.Imp = make([]openrtb2.Imp, len(request.Imp))
55+
copy(requestCopy.Imp, request.Imp)
56+
preProcess(&requestCopy)
57+
reqBody, err := jsonutil.Marshal(&requestCopy)
58+
if err != nil {
59+
return nil, err
60+
}
61+
headers := http.Header{}
62+
headers.Add("Content-Type", "application/json;charset=utf-8")
63+
headers.Add("Accept", "application/json")
64+
headers.Add("x-openrtb-version", "2.6")
65+
return &adapters.RequestData{
66+
Method: "POST",
67+
Uri: endPoint,
68+
Body: reqBody,
69+
Headers: headers,
70+
ImpIDs: openrtb_ext.GetImpIDs(request.Imp),
71+
}, nil
72+
}
73+
74+
// getSuperEdgeExt extracts ExtSuperEdge from the first imp's ext.bidder.
75+
func getSuperEdgeExt(request *openrtb2.BidRequest) (*openrtb_ext.ExtSuperEdge, error) {
76+
var extSuperEdge openrtb_ext.ExtSuperEdge
77+
78+
var extBidder adapters.ExtImpBidder
79+
if err := jsonutil.Unmarshal(request.Imp[0].Ext, &extBidder); err != nil {
80+
return nil, err
81+
}
82+
83+
if err := jsonutil.Unmarshal(extBidder.Bidder, &extSuperEdge); err != nil {
84+
return nil, err
85+
}
86+
87+
return &extSuperEdge, nil
88+
}
89+
90+
func (a *adapter) getEndPoint(ext *openrtb_ext.ExtSuperEdge) (string, error) {
91+
endPointParams := macros.EndpointTemplateParams{
92+
Host: url.PathEscape(getRegionHost(ext.Region)),
93+
AccountID: url.PathEscape(ext.Sk),
94+
}
95+
return macros.ResolveMacros(a.EndpointTemplate, endPointParams)
96+
}
97+
98+
func getRegionHost(region string) string {
99+
switch region {
100+
case "EU":
101+
return "rtb-eu"
102+
case "APAC":
103+
return "rtb-sg"
104+
default:
105+
return "rtb-us"
106+
}
107+
}
108+
109+
func preProcess(request *openrtb2.BidRequest) {
110+
for i := range request.Imp {
111+
if request.Imp[i].Banner != nil {
112+
banner := *request.Imp[i].Banner
113+
if (banner.W == nil || banner.H == nil || *banner.W == 0 || *banner.H == 0) && len(banner.Format) > 0 {
114+
firstFormat := banner.Format[0]
115+
banner.W = &firstFormat.W
116+
banner.H = &firstFormat.H
117+
request.Imp[i].Banner = &banner
118+
}
119+
}
120+
}
121+
}
122+
123+
func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, _ *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
124+
if adapters.IsResponseStatusCodeNoContent(response) {
125+
return nil, nil
126+
}
127+
if err := adapters.CheckResponseStatusCodeForErrors(response); err != nil {
128+
return nil, []error{err}
129+
}
130+
var bidResp openrtb2.BidResponse
131+
if err := jsonutil.Unmarshal(response.Body, &bidResp); err != nil {
132+
return nil, []error{err}
133+
}
134+
bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
135+
if bidResp.Cur != "" {
136+
bidResponse.Currency = bidResp.Cur
137+
}
138+
var errs []error
139+
for _, seatBid := range bidResp.SeatBid {
140+
for idx := range seatBid.Bid {
141+
bidType, err := getBidType(seatBid.Bid[idx], internalRequest.Imp)
142+
if err != nil {
143+
errs = append(errs, err)
144+
} else {
145+
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
146+
Bid: &seatBid.Bid[idx],
147+
BidType: bidType,
148+
})
149+
}
150+
}
151+
}
152+
return bidResponse, errs
153+
}
154+
155+
func getBidType(bid openrtb2.Bid, imps []openrtb2.Imp) (openrtb_ext.BidType, error) {
156+
switch bid.MType {
157+
case openrtb2.MarkupBanner:
158+
return openrtb_ext.BidTypeBanner, nil
159+
case openrtb2.MarkupNative:
160+
return openrtb_ext.BidTypeNative, nil
161+
default:
162+
for _, imp := range imps {
163+
if imp.ID == bid.ImpID {
164+
if imp.Banner != nil && imp.Native == nil {
165+
return openrtb_ext.BidTypeBanner, nil
166+
}
167+
if imp.Native != nil && imp.Banner == nil {
168+
return openrtb_ext.BidTypeNative, nil
169+
}
170+
}
171+
}
172+
return "", &errortypes.BadServerResponse{
173+
Message: fmt.Sprintf("Unsupported MType %d", bid.MType),
174+
}
175+
}
176+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package superedge
2+
3+
import (
4+
"encoding/json"
5+
"testing"
6+
"text/template"
7+
8+
"github.com/prebid/openrtb/v20/openrtb2"
9+
"github.com/stretchr/testify/assert"
10+
11+
"github.com/prebid/prebid-server/v4/adapters/adapterstest"
12+
"github.com/prebid/prebid-server/v4/config"
13+
"github.com/prebid/prebid-server/v4/openrtb_ext"
14+
)
15+
16+
func TestJsonSamples(t *testing.T) {
17+
bidder, buildErr := Builder(openrtb_ext.BidderSuperEdge, config.Adapter{
18+
Endpoint: "https://{{.Host}}.superedge.co.jp/bid?sk={{.AccountID}}"}, config.Server{ExternalUrl: "http://hosturl.com"})
19+
20+
if buildErr != nil {
21+
t.Fatalf("Builder returned unexpected error %v", buildErr)
22+
}
23+
24+
adapterstest.RunJSONBidderTest(t, "superedgetest", bidder)
25+
}
26+
27+
func TestEndpointTemplateMalformed(t *testing.T) {
28+
_, buildErr := Builder(openrtb_ext.BidderSuperEdge, config.Adapter{Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com"})
29+
30+
assert.Error(t, buildErr)
31+
}
32+
33+
func TestMakeRequestGetEndPointError(t *testing.T) {
34+
badTmpl, _ := template.New("").Parse("http://example.com/bid?sk={{.sk}}{{template \"nonexistent\" .}}")
35+
a := &adapter{EndpointTemplate: badTmpl}
36+
37+
request := &openrtb2.BidRequest{
38+
Imp: []openrtb2.Imp{
39+
{
40+
ID: "test-imp-id",
41+
Ext: json.RawMessage(`{"bidder":{"sk":"test-sk"}}`),
42+
},
43+
},
44+
}
45+
46+
_, err := a.makeRequest(request)
47+
assert.Error(t, err)
48+
}
49+
50+
func TestGetBidTypeAmbiguous(t *testing.T) {
51+
bid := openrtb2.Bid{ImpID: "imp-1"}
52+
imps := []openrtb2.Imp{
53+
{
54+
ID: "imp-1",
55+
Banner: &openrtb2.Banner{},
56+
Native: &openrtb2.Native{},
57+
},
58+
}
59+
_, err := getBidType(bid, imps)
60+
assert.Error(t, err)
61+
assert.Contains(t, err.Error(), "Unsupported MType")
62+
}
63+
64+
func TestGetBidTypeNoMatchingImp(t *testing.T) {
65+
bid := openrtb2.Bid{ImpID: "imp-1"}
66+
imps := []openrtb2.Imp{
67+
{ID: "imp-2", Banner: &openrtb2.Banner{}},
68+
}
69+
_, err := getBidType(bid, imps)
70+
assert.Error(t, err)
71+
}
72+
73+
func TestGetBidTypeNoMediaType(t *testing.T) {
74+
bid := openrtb2.Bid{ImpID: "imp-1"}
75+
imps := []openrtb2.Imp{
76+
{ID: "imp-1"},
77+
}
78+
_, err := getBidType(bid, imps)
79+
assert.Error(t, err)
80+
}

0 commit comments

Comments
 (0)