-
Notifications
You must be signed in to change notification settings - Fork 760
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: Pixfuture #4117
base: master
Are you sure you want to change the base?
New Adapter: Pixfuture #4117
Changes from 14 commits
93e6573
458fad1
d67a079
a9fe81b
606b185
061b818
d0bc2e1
eec17ff
cb8e3a7
bba6eed
22df0f8
3f33089
a22b19e
993f157
284c847
9e470a0
3b4ca26
1df8f71
6a59158
2ba1a64
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,25 @@ | ||
mode: set | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:20.119,24.2 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:27.137,28.27 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:28.27,30.3 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:31.2,32.16 2 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:32.16,34.3 1 0 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:36.2,44.50 2 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:48.72,49.20 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:49.20,52.41 3 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:52.41,54.4 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:57.2,59.3 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:63.166,64.53 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:64.53,66.3 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:68.2,68.54 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:68.54,72.3 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:74.2,74.46 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:74.46,78.3 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:80.2,81.73 2 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:81.73,83.3 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:85.2,89.43 4 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:89.43,90.35 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:90.35,92.18 2 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:92.18,94.13 2 0 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:96.4,99.6 1 1 | ||
github.com/prebid/prebid-server/v3/adapters/pixfuture/pixfuture.go:103.2,103.28 1 1 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package pixfuture | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/prebid/prebid-server/v3/openrtb_ext" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestPixfutureParams(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
params openrtb_ext.ImpExtPixfuture | ||
expectedError string | ||
}{ | ||
{ | ||
name: "Valid Params", | ||
params: openrtb_ext.ImpExtPixfuture{ | ||
PlacementID: "123", | ||
}, | ||
expectedError: "", | ||
}, | ||
{ | ||
name: "Missing PlacementID", | ||
params: openrtb_ext.ImpExtPixfuture{ | ||
PlacementID: "", | ||
}, | ||
expectedError: "PlacementID is required", | ||
}, | ||
} | ||
|
||
for _, test := range testCases { | ||
t.Run(test.name, func(t *testing.T) { | ||
err := validatePixfutureParams(test.params) | ||
if test.expectedError == "" { | ||
assert.NoError(t, err) | ||
} else { | ||
assert.EqualError(t, err, test.expectedError) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func validatePixfutureParams(params openrtb_ext.ImpExtPixfuture) error { | ||
if params.PlacementID == "" { | ||
return fmt.Errorf("PlacementID is required") | ||
} | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package pixfuture | ||
|
||
import ( | ||
"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 | ||
} | ||
|
||
// Builder builds a new instance of the Pixfuture adapter. | ||
func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { | ||
return &adapter{ | ||
endpoint: config.Endpoint, | ||
}, nil | ||
} | ||
|
||
// MakeRequests prepares and serializes HTTP requests to be sent to the Pixfuture endpoint. | ||
func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { | ||
if len(request.Imp) == 0 { | ||
return nil, []error{&errortypes.BadInput{Message: "No impressions in the bid request"}} | ||
} | ||
requestJSON, err := jsonutil.Marshal(request) | ||
if err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
requestData := &adapters.RequestData{ | ||
Method: "POST", | ||
Uri: a.endpoint, | ||
Body: requestJSON, | ||
Headers: http.Header{ | ||
"Content-Type": []string{"application/json"}, | ||
}, | ||
} | ||
return []*adapters.RequestData{requestData}, nil | ||
} | ||
|
||
// getMediaTypeForBid extracts the bid type based on the bid extension data. | ||
func getMediaTypeForBid(bid openrtb2.Bid) (openrtb_ext.BidType, error) { | ||
if bid.Ext != nil { | ||
var bidExt openrtb_ext.ExtBid | ||
err := jsonutil.Unmarshal(bid.Ext, &bidExt) | ||
if err == nil && bidExt.Prebid != nil { | ||
return openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) | ||
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. Consider this as a suggestion. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, recommends implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression. |
||
} | ||
} | ||
|
||
return "", &errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Failed to parse impression \"%s\" mediatype", bid.ImpID), | ||
} | ||
} | ||
|
||
// MakeBids parses the HTTP response from the Pixfuture endpoint and generates a BidderResponse. | ||
func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { | ||
if responseData.StatusCode == http.StatusNoContent { | ||
return nil, nil | ||
} | ||
|
||
if responseData.StatusCode == http.StatusBadRequest { | ||
return nil, []error{&errortypes.BadInput{ | ||
Message: "Unexpected status code: 400. Bad request from publisher. Run with request.debug = 1 for more info.", | ||
}} | ||
} | ||
|
||
if responseData.StatusCode != http.StatusOK { | ||
return nil, []error{&errortypes.BadServerResponse{ | ||
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), | ||
}} | ||
} | ||
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. This is correct but you could also use the common code as below -
|
||
|
||
var response openrtb2.BidResponse | ||
if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { | ||
return nil, []error{err} | ||
} | ||
|
||
bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) | ||
bidResponse.Currency = response.Cur | ||
var errors []error | ||
|
||
for _, seatBid := range response.SeatBid { | ||
for i, bid := range seatBid.Bid { | ||
bidType, err := getMediaTypeForBid(bid) | ||
if err != nil { | ||
errors = append(errors, err) | ||
continue | ||
} | ||
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ | ||
Bid: &seatBid.Bid[i], | ||
BidType: bidType, | ||
}) | ||
} | ||
} | ||
|
||
return bidResponse, errors | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package pixfuture | ||
|
||
import ( | ||
"encoding/json" | ||
"net/http" | ||
"testing" | ||
|
||
"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/openrtb_ext" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestBuilder(t *testing.T) { | ||
adapter, err := Builder("pixfuture", config.Adapter{Endpoint: "https://mock-endpoint.com"}, config.Server{}) | ||
assert.NoError(t, err, "unexpected error during Builder execution") | ||
assert.NotNil(t, adapter, "expected a non-nil adapter instance") | ||
} | ||
|
||
func TestAdapter_MakeRequests(t *testing.T) { | ||
adapter := &adapter{endpoint: "https://mock-pixfuture-endpoint.com"} | ||
|
||
t.Run("Valid Request", func(t *testing.T) { | ||
bidRequest := &openrtb2.BidRequest{ | ||
ID: "test-request-id", | ||
Imp: []openrtb2.Imp{ | ||
{ | ||
ID: "test-imp-id", | ||
Banner: &openrtb2.Banner{W: int64Ptr(300), H: int64Ptr(250)}, | ||
Ext: jsonRawExt(`{"bidder":{"siteId":"123"}}`), | ||
}, | ||
}, | ||
} | ||
|
||
requests, errs := adapter.MakeRequests(bidRequest, nil) | ||
assert.Empty(t, errs, "unexpected errors in MakeRequests") | ||
assert.Equal(t, 1, len(requests), "expected exactly one request") | ||
|
||
request := requests[0] | ||
assert.Equal(t, "POST", request.Method, "unexpected HTTP method") | ||
assert.Equal(t, "https://mock-pixfuture-endpoint.com", request.Uri, "unexpected request URI") | ||
assert.Contains(t, string(request.Body), `"id":"test-request-id"`, "unexpected request body") | ||
assert.Equal(t, "application/json", request.Headers.Get("Content-Type"), "unexpected content-type") | ||
}) | ||
|
||
t.Run("No Impressions", func(t *testing.T) { | ||
bidRequest := &openrtb2.BidRequest{ID: "test-request-id"} | ||
|
||
requests, errs := adapter.MakeRequests(bidRequest, nil) | ||
assert.NotEmpty(t, errs, "expected error for request with no impressions") | ||
assert.Nil(t, requests, "expected no requests for request with no impressions") | ||
}) | ||
|
||
t.Run("Malformed BidRequest", func(t *testing.T) { | ||
bidRequest := &openrtb2.BidRequest{} | ||
|
||
requests, errs := adapter.MakeRequests(bidRequest, nil) | ||
assert.NotEmpty(t, errs, "expected error for malformed request") | ||
assert.Nil(t, requests, "expected no requests for malformed request") | ||
}) | ||
} | ||
|
||
func TestAdapter_MakeBids(t *testing.T) { | ||
adapter := &adapter{} | ||
|
||
t.Run("Valid Response", func(t *testing.T) { | ||
responseData := &adapters.ResponseData{ | ||
StatusCode: http.StatusOK, | ||
Body: []byte(`{ | ||
"id": "test-response-id", | ||
"seatbid": [{ | ||
"bid": [{ | ||
"id": "test-bid-id", | ||
"impid": "test-imp-id", | ||
"price": 1.23, | ||
"adm": "<html>Ad Content</html>", | ||
"crid": "creative-123", | ||
"w": 300, | ||
"h": 250, | ||
"ext": {"prebid":{"type":"banner"}} | ||
}] | ||
}], | ||
"cur": "USD" | ||
}`), | ||
} | ||
|
||
bidRequest := &openrtb2.BidRequest{ID: "test-request-id", Imp: []openrtb2.Imp{{ID: "test-imp-id"}}} | ||
bidResponse, errs := adapter.MakeBids(bidRequest, nil, responseData) | ||
|
||
assert.Empty(t, errs, "unexpected errors in MakeBids") | ||
assert.NotNil(t, bidResponse, "expected bid response") | ||
assert.Equal(t, "USD", bidResponse.Currency, "unexpected currency") | ||
assert.Equal(t, 1, len(bidResponse.Bids), "expected one bid") | ||
|
||
bid := bidResponse.Bids[0] | ||
assert.Equal(t, "test-bid-id", bid.Bid.ID, "unexpected bid ID") | ||
assert.Equal(t, "test-imp-id", bid.Bid.ImpID, "unexpected impression ID") | ||
assert.Equal(t, 1.23, bid.Bid.Price, "unexpected bid price") | ||
assert.Equal(t, openrtb_ext.BidTypeBanner, bid.BidType, "unexpected bid type") | ||
}) | ||
|
||
t.Run("No Content Response", func(t *testing.T) { | ||
responseData := &adapters.ResponseData{StatusCode: http.StatusNoContent} | ||
bidRequest := &openrtb2.BidRequest{} | ||
bidResponse, errs := adapter.MakeBids(bidRequest, nil, responseData) | ||
assert.Nil(t, bidResponse, "expected no bid response") | ||
assert.Empty(t, errs, "unexpected errors for no content response") | ||
}) | ||
|
||
t.Run("Bad Request Response", func(t *testing.T) { | ||
responseData := &adapters.ResponseData{StatusCode: http.StatusBadRequest} | ||
bidRequest := &openrtb2.BidRequest{} | ||
bidResponse, errs := adapter.MakeBids(bidRequest, nil, responseData) | ||
assert.Nil(t, bidResponse, "expected no bid response") | ||
assert.NotEmpty(t, errs, "expected errors for bad request response") | ||
}) | ||
|
||
t.Run("Unexpected Status Code", func(t *testing.T) { | ||
responseData := &adapters.ResponseData{StatusCode: http.StatusInternalServerError} | ||
bidRequest := &openrtb2.BidRequest{} | ||
bidResponse, errs := adapter.MakeBids(bidRequest, nil, responseData) | ||
assert.Nil(t, bidResponse, "expected no bid response") | ||
assert.NotEmpty(t, errs, "expected errors for unexpected status code") | ||
}) | ||
|
||
t.Run("Malformed Response Body", func(t *testing.T) { | ||
responseData := &adapters.ResponseData{ | ||
StatusCode: http.StatusOK, | ||
Body: []byte(`malformed response`), | ||
} | ||
bidRequest := &openrtb2.BidRequest{} | ||
bidResponse, errs := adapter.MakeBids(bidRequest, nil, responseData) | ||
assert.Nil(t, bidResponse, "expected no bid response") | ||
assert.NotEmpty(t, errs, "expected errors for malformed response body") | ||
}) | ||
} | ||
|
||
func TestGetMediaTypeForBid(t *testing.T) { | ||
t.Run("Valid Bid Ext", func(t *testing.T) { | ||
bid := openrtb2.Bid{ | ||
ID: "test-bid", | ||
Ext: json.RawMessage(`{"prebid":{"type":"banner"}}`), | ||
} | ||
bidType, err := getMediaTypeForBid(bid) | ||
assert.NoError(t, err, "unexpected error in getMediaTypeForBid") | ||
assert.Equal(t, openrtb_ext.BidTypeBanner, bidType, "unexpected bid type") | ||
}) | ||
|
||
t.Run("Invalid Bid Ext", func(t *testing.T) { | ||
bid := openrtb2.Bid{ | ||
ID: "test-bid", | ||
Ext: json.RawMessage(`{"invalid":"data"}`), | ||
} | ||
bidType, err := getMediaTypeForBid(bid) | ||
assert.Error(t, err, "expected error for invalid bid ext") | ||
assert.Equal(t, openrtb_ext.BidType(""), bidType, "expected empty bid type for invalid bid ext") | ||
}) | ||
} | ||
|
||
func int64Ptr(i int64) *int64 { | ||
return &i | ||
} | ||
|
||
func jsonRawExt(jsonStr string) json.RawMessage { | ||
return json.RawMessage(jsonStr) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"id": "test-request-id", | ||
"imp": [ | ||
{ | ||
"id": "test-imp-id", | ||
"banner": { | ||
"w": 300, | ||
"h": 250 | ||
}, | ||
"ext": { | ||
"bidder": { | ||
"siteId": "123" | ||
} | ||
} | ||
} | ||
], | ||
"site": { | ||
"page": "http://example.com" | ||
}, | ||
"device": { | ||
"ua": "Mozilla/5.0", | ||
"ip": "192.168.0.1" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"id": "test-response-id", | ||
"seatbid": [ | ||
{ | ||
"bid": [ | ||
{ | ||
"id": "test-bid-id", | ||
"impid": "test-imp-id", | ||
"price": 1.23, | ||
"adm": "<html>Ad Content</html>", | ||
"crid": "creative-123", | ||
"w": 300, | ||
"h": 250, | ||
"ext": { | ||
"prebid": { | ||
"type": "banner" | ||
} | ||
} | ||
} | ||
] | ||
} | ||
], | ||
"cur": "USD" | ||
} |
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.
This check is not required here as this is being checked in the core codebase already. Here is the link -
prebid-server/endpoints/openrtb2/auction.go
Lines 770 to 772 in 32fdbc4