Skip to content
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: AdUp Tech #4076

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

danygielow
Copy link

@danygielow danygielow commented Nov 26, 2024

Hello,

We as AdUp Technology want to add our own Prebid Server Adapter.
We already have a PrebidJS Adapter.

Docs: prebid/prebid.github.io#5728

}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {

Choose a reason for hiding this comment

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

Consider this as a suggestion. The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to openrtb_ext.BidTypeBanner. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression.

}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {

Choose a reason for hiding this comment

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

Consider this as a suggestion. The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to openrtb_ext.BidTypeNative. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression.

Copy link

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 74112fe

aduptech

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:23:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:32:	MakeRequests	53.8%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:63:	convertCurrency	0.0%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:90:	MakeBids	63.6%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:136:	getBidType	75.0%
total:									(statements)	49.1%

}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {

Choose a reason for hiding this comment

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

Consider this as a suggestion. The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to openrtb_ext.BidTypeBanner. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression.

}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {

Choose a reason for hiding this comment

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

Consider this as a suggestion. The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to openrtb_ext.BidTypeNative. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression.

Copy link
Author

Choose a reason for hiding this comment

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

What should be changed here? I assume this check is wrong, because we do exactly what the comment suggests.

Copy link
Contributor

Choose a reason for hiding this comment

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

💯 this suggestion (x3?) is not very helpful

Copy link

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 8e94b4b

aduptech

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:23:	Builder		100.0%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:32:	MakeRequests	84.6%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:63:	convertCurrency	75.0%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:90:	MakeBids	63.6%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:136:	getBidType	75.0%
total:									(statements)	73.6%

@bsardo bsardo added the adapter label Jan 6, 2025
@bsardo
Copy link
Collaborator

bsardo commented Jan 6, 2025

@scr-oath can you please review?

@bsardo
Copy link
Collaborator

bsardo commented Jan 7, 2025

@pm-isha-bharti can you please review?

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
bidder := &adapter{
endpoint: config.Endpoint,
target_currency: "EUR",
Copy link
Contributor

Choose a reason for hiding this comment

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

question: Can this go into ExtraAdapterInfo (either directly or as json that's parsed or inspected maybe with gjson.Get) rather than being hard coded?

Copy link
Author

Choose a reason for hiding this comment

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

Changed to use ExtraAdapterInfo.


convertedValue, err := a.convertCurrency(imp.BidFloor, imp.BidFloorCur, reqInfo)
if err != nil {
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: This return doesn't seem right - as it should be []error - perhaps, if convertCurrency returns a []error, it should be named errs rather than err which suggests a single error as the type.

Copy link
Author

Choose a reason for hiding this comment

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

convertCurrency doesn't have to return []error. Refactored to just return a single error.

}

requestData := &adapters.RequestData{
Method: "POST",
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Method: "POST",
Method: http.MethodPost,


// try again by first converting to USD
// then convert to target_currency
convertedValue, err = reqInfo.ConvertCurrency(value, cur, "USD")
Copy link
Contributor

Choose a reason for hiding this comment

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

observation we should have constants or an enum of valid currencies… you can ignore for this PR but just making the note; filed #4134

Comment on lines 91 to 115
if responseData.StatusCode == http.StatusNoContent {
return nil, nil
}

if responseData.StatusCode == http.StatusBadRequest {
err := &errortypes.BadInput{
Message: "Unexpected status code: 400. Run with request.debug = 1 for more info.",
}
return nil, []error{err}
}

if responseData.StatusCode != http.StatusOK {
err := &errortypes.BadServerResponse{
Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode),
}
return nil, []error{err}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

question: would a switch on the statusCode (with empty for ok and default clause for this everything-else case) be more readable?

Copy link
Author

Choose a reason for hiding this comment

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

Refactored into a switch

Comment on lines 118 to 140
for _, seatBid := range response.SeatBid {
for i, bid := range seatBid.Bid {
bidType, err := getBidType(bid.MType)
if err != nil {
errs = append(errs, err)
continue
}

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

Choose a reason for hiding this comment

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

suggestion: I don't like making copies of the seatbid and bid in a loop

Suggested change
for _, seatBid := range response.SeatBid {
for i, bid := range seatBid.Bid {
bidType, err := getBidType(bid.MType)
if err != nil {
errs = append(errs, err)
continue
}
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: &seatBid.Bid[i],
BidType: bidType,
})
}
}
for i := range response.SeatBid {
seatBid = &response.SeatBid[i]
for j := range seatBid.Bid {
bid := &seatBid.Bid[j]
bidType, err := getBidType(bid.MType)
if err != nil {
errs = append(errs, err)
continue
}
bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
Bid: bid,
BidType: bidType,
})
}
}

Copy link
Author

Choose a reason for hiding this comment

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

Used your suggestion

}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {
Copy link
Contributor

Choose a reason for hiding this comment

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

💯 this suggestion (x3?) is not very helpful

Comment on lines 15 to 17
if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if buildErr != nil {
t.Fatalf("Builder returned unexpected error %v", buildErr)
}
if buildErr != nil {
assert.NoError(t, buildErr, "Builder returned unexpected error")
}

Copy link
Author

Choose a reason for hiding this comment

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

Ah, good to know. This is our first time working in Go.

Copy link
Contributor

@scr-oath scr-oath Jan 8, 2025

Choose a reason for hiding this comment

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

suggestion: Change assert to require

For what it's worth, I realize you were calling fatal before so I realize you need the require.NoError - assertions from the assert module continue but the test fails whereas those from require halt immediately. This is kind of like google's gtest with its two variants for each assertion so when you can continue you report more/all things that fail but when you can't, you don't.

Comment on lines 59 to 61
if err := validator.Validate(openrtb_ext.BidderAdUpTech, json.RawMessage(invalidParam)); err == nil {
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if err := validator.Validate(openrtb_ext.BidderAdUpTech, json.RawMessage(invalidParam)); err == nil {
t.Errorf("Schema allowed unexpected params: %s", invalidParam)
}
assert.NoErrorf(t, validator.Validate(openrtb_ext.BidderAdUpTech, json.RawMessage(invalidParam)), "Schema allowed unexpected params: %s", invalidParam)

Copy link
Author

Choose a reason for hiding this comment

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

using assert.Errorf here, but otherwise used the suggestion.

Copy link
Contributor

@scr-oath scr-oath left a comment

Choose a reason for hiding this comment

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

I didn't mean to approve before… I thought I had ticked request changes…

@derfryday derfryday force-pushed the feat/add-aduptech-adapter branch from 8e94b4b to 2ad858d Compare January 8, 2025 07:54
}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {
Copy link

Choose a reason for hiding this comment

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

Consider this as a suggestion. The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to openrtb_ext.BidTypeBanner. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression.

}

func getBidType(markupType openrtb2.MarkupType) (openrtb_ext.BidType, error) {
switch markupType {
Copy link

Choose a reason for hiding this comment

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

Consider this as a suggestion. The current implementation follows an anti-pattern, assumes that if there is a multi-format request, the media type defaults to openrtb_ext.BidTypeNative. Prebid server expects the media type to be explicitly set in the adapter response. Therefore, we strongly recommend implementing a pattern where the adapter server sets the MType field in the response to accurately determine the media type for the impression.

Copy link

github-actions bot commented Jan 8, 2025

Code coverage summary

Note:

  • Prebid team doesn't anticipate tests covering code paths that might result in marshal and unmarshal errors
  • Coverage summary encompasses all commits leading up to the latest one, 2ad858d

aduptech

Refer here for heat map coverage report

github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:27:	Builder		80.0%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:41:	MakeRequests	84.6%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:72:	convertCurrency	75.0%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:99:	MakeBids	71.4%
github.com/prebid/prebid-server/v3/adapters/aduptech/aduptech.go:145:	getBidType	75.0%
total:									(statements)	76.4%

- banner
- native
userSync:
redirect:
Copy link
Contributor

@pm-isha-bharti pm-isha-bharti Jan 8, 2025

Choose a reason for hiding this comment

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

@danygielow The usersync URL returned by the /cookie_sync for aduptech is currently throwing 404. Can you please check if the URLs added for userSync are correct?

func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) {
switch responseData.StatusCode {
case http.StatusNoContent:
return nil, nil
Copy link
Contributor

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 where your mock response returns a 204 status code.


var response openrtb2.BidResponse
if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil {
return nil, []error{err}
Copy link
Contributor

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 where your mock response returns a bid response that fails to unmarshal successfully. This can be achieved by setting one of the fields to an incorrect data type.

switch responseData.StatusCode {
case http.StatusNoContent:
return nil, nil
case http.StatusBadRequest:
Copy link
Contributor

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 where your mock response returns a 400 status code.

func (a *adapter) convertCurrency(value float64, cur string, reqInfo *adapters.ExtraRequestInfo) (float64, error) {
convertedValue, err := reqInfo.ConvertCurrency(value, cur, a.extraInfo.TargetCurrency)

if err != nil {
Copy link
Contributor

@pm-isha-bharti pm-isha-bharti Jan 8, 2025

Choose a reason for hiding this comment

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

Please add supplemental JSONs for currency conversion failures

bidder, buildErr := Builder(openrtb_ext.BidderAdUpTech, config.Adapter{
Endpoint: "https://example.com/rtb/bid", ExtraAdapterInfo: "{\"target_currency\": \"EUR\"}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"})

assert.NoError(t, buildErr, "Builder returned unexpected error")
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
assert.NoError(t, buildErr, "Builder returned unexpected error")
require.NoError(t, buildErr, "Builder returned unexpected error")

package aduptech

import (
"github.com/stretchr/testify/assert"
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

}

for _, validParam := range validParams {
assert.NoErrorf(t, validator.Validate(openrtb_ext.BidderAdUpTech, json.RawMessage(validParam)), "Schema rejected Aduptech params: %s", validParam)
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, assert seems correct here as you want all failing assertions reported

@bsardo
Copy link
Collaborator

bsardo commented Jan 8, 2025

Hi @danygielow, @derfryday, now that the review process has begun, can you please push new commits when making changes instead of rebasing and force pushing? It will save reviewers a lot of time when performing delta reviews. All of the commits will be squashed when we merge. Thanks!

func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) {
var extraInfo ExtraInfo
if err := jsonutil.Unmarshal([]byte(config.ExtraAdapterInfo), &extraInfo); err != nil {
return nil, fmt.Errorf("invalid extra info: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: Use %w instead - see https://pkg.go.dev/fmt#Errorf

Suggested change
return nil, fmt.Errorf("invalid extra info: %v", err)
return nil, fmt.Errorf("invalid extra info: %w", err)

return nil, []error{err}
}

imp.BidFloorCur = a.extraInfo.TargetCurrency
Copy link
Contributor

@scr-oath scr-oath Jan 9, 2025

Choose a reason for hiding this comment

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

bug?: There seems like a bug in here somewhere… the convertCurrency has a path that can handle errors and, instead, convert to "USD" - how is that choice made here if you always set the BidFloorCur to a.extraInfo.TargetCurrency - should you pass in a pointer to the extraInfo and set the chosen currency in the convertCurrency method maybe? or return the choice back and set to that? Style is your choice, but I think that's an unhandled case and might deserve some unit tests to prove it works as intended.


if err != nil {
var convErr currency.ConversionNotFoundError
if errors.As(err, &convErr) {
Copy link
Contributor

@scr-oath scr-oath Jan 9, 2025

Choose a reason for hiding this comment

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

nitpick/suggestion: In go, there's a pattern that you try to take the "terminal" case first - return/break/panic/exit so that you don't need an else clause - it saves "cognitive overload" because you can just reason that everything after is the "happy path" (not having your brain full with remembering what the condition was when you get to the else way down the screen or having to scroll back up to understand it) - and also saves precious indentation 😄

(so make this !errors.As and pull the else clause into the block and remove the curly braces {} (keeping and unindenting this code))

Publisher string `json:"publisher"`
Placement string `json:"placement"`
Query string `json:"query"`
AdTest string `json:"adtest"`
Copy link
Contributor

@pm-isha-bharti pm-isha-bharti Jan 10, 2025

Choose a reason for hiding this comment

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

Can we use bidrequest.test instead of introducing a separate parameter, considering it is a standard ORTB field already used by Prebid?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants