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: Adnuntius #2014

Merged
merged 24 commits into from
Oct 29, 2021
Merged

New Adapter: Adnuntius #2014

merged 24 commits into from
Oct 29, 2021

Conversation

mikael-lundin
Copy link
Contributor

Hi, this is a pull request for a new adapter that will be for adnuntius adserver. This is my first time using go, please be gentle and if there's anything you need just tell me and I'll provide. :)

@bsardo
Copy link
Collaborator

bsardo commented Sep 28, 2021

Hi @mikael-lundin. Thanks for your submission. We'll get to this shortly but could you open up a docs PR here in the meantime?

@mikael-lundin
Copy link
Contributor Author

I've added information about server side here. :)
prebid/prebid.github.io#3312

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

@mikael-lundin Nice work; I left you some comments. Let me know if you have any questions.

static/bidder-info/adnuntius.yaml Outdated Show resolved Hide resolved
adapters/adnuntius/params_test.go Outdated Show resolved Hide resolved
adapters/adnuntius/params_test.go Show resolved Hide resolved
adapters/adnuntius/adnuntius.go Outdated Show resolved Hide resolved
adapters/adnuntius/adnuntius.go Outdated Show resolved Hide resolved
adapters/adnuntius/adnuntius.go Outdated Show resolved Hide resolved
if len(adunit.Ads) > 0 {
ad := adunit.Ads[0]

currency = ad.Bid.Currency
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm curious about what you're doing with currency. Currency is set on the bidResponse. It looks like you iterate over all ad units and only process the first ad for an adunit. You're then setting the currency to that ad's bid currency. That means that the currency you select will be the currency of the last ad you process since you're assigning currency to bidResponse.currency on line 298 after you're done iterating over all adunits. This should be fine if it is guaranteed all ad bids will have currency set.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, this is just me getting around how our ad server works. there will always be a currency set in the ad unit response.

Comment on lines +273 to +282
domainArray := strings.Split(url, "/")
domain := strings.Replace(domainArray[2], "www.", "", -1)
adDomain = append(adDomain, domain)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are the destination URLs always going to start with http(s)://?
Nitpick: maybe split on // and grab domainArray[1] instead? IMO that seems a little more straightforward.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that seems like a good idea but I got the impression that i was only allowed to send the top level domain in that field? :D If not I can just stop what that stuff is doing and just pass the entire url. And yes, we force the url to have http(s)://

@mikael-lundin
Copy link
Contributor Author

As a general note, I think I've managed to fix the issues mentioned in this pull request, please let me know if I'm missing anything. :)

errors = append(errors, &errortypes.BadInput{
Message: fmt.Sprintf("Error unmarshalling ExtImpBmtm: %s", err.Error()),
})
}
Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 Oct 12, 2021

Choose a reason for hiding this comment

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

In case of error occurs, lines 128, 134 and 141 - should you just return an error or skip to next imp?
Edit: Similar to what you do in MakeBids

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hopefully I've done it as you meant it in my coming commit.

Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 Oct 17, 2021

Choose a reason for hiding this comment

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

Thank you for the update.
Please check it one more time. You probably don't want to collect all errors. Instead return after first error occurrence. If so please modify return []error to just error and return it immediately.
Edit: Please check same thing in other functions

@@ -1,9 +1,10 @@
maintainer:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please change the indentation in this file to 2 spaces instead of 4 to meet the recommended yaml spacing.

}

var network string
network := "default"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: How about making this a constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is because it might change in the lines below, so making it a constant is not correct, I think? :) but then again my first go at golang, (pun intended) so i might be mistaking.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry I mean define a constant at the top of the file (e.g. const defaultNetwork = "default")and assign it to network here.

@@ -153,11 +156,9 @@ func (a *adapter) generateRequests(ortbRequest openrtb2.BidRequest) ([]*adapters
})
}

var site string
site := "unknown"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: How about making this a constant?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above, it might change further down.

return "", []error{fmt.Errorf("failed to parse Adnuntius endpoint: %v", err)}
}

_, offset := a.tzo.Now().UTC().Local().Zone()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for injecting the clock when instantiating the adapter. This line though is still causing a problem when running the tests locally because of the call to Local() which will consult the TZ environment variable to determine the timezone.
Regardless, I think we can simplify this line to _, offset := a.tzo.Now().Zone() which will also fix this issue.
Now() returns the local timezone so whatever zone you specify when defining your fake time for testing purposes will be the local time.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, have changed this and really hope it works for you now! :D

@@ -0,0 +1,23 @@
package adnuntius
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you can delete this file; I apologize for asking you to create it. Instead, would you please use what's defined in util/timeutil/time.go?
In the Builder function you should be able to instantiate like this:

bidder := &adapter{
	time:     &timeutil.RealTime{},
	endpoint: config.Endpoint,
}

And then in your test you can do this:

// FakeTime implements the Time interface
type FakeTime struct {
	time time.Time
}

func (ft *FakeTime) Now() time.Time {
	return ft.time
}

func replaceRealTimeWithKnownTime(bidder adapters.Bidder) {
	bidderAdnuntius, _ := bidder.(*adapter)
	bidderAdnuntius.time = &FakeTime {
		time: time.Date(2016, 1, 1, 12, 30, 15, 0, time.UTC),
	}
}

Copy link
Collaborator

Choose a reason for hiding this comment

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

Please delete this file since it's not used anymore.


type QueryString map[string]string
type adapter struct {
tzo timezone
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: I suggest calling this something else like time or clock perhaps since it isn't a timezone but rather a time.

}

_, offset := a.tzo.Now().UTC().Local().Zone()
tzo := -offset / 3600 * 60
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nitpick: how about making the denominator a constant?

}}
}

if response.StatusCode != http.StatusOK {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I suggest keeping an error code catch-all in case something goes wrong on your server so PBS can handle it gracefully.

"currency": "NOK"
},
"adId": "adn-id-1559784094",
"creativeWidth": 980,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a valid scenario but you're not getting test coverage of lines if Werr != nil { and if len(adsErr) > 0 {. If you change this to a string that doesn't parse to an int (e.g. "ABC"), the call to ParseInt will return the error as Werr giving you the code coverage.

},
"adId": "adn-id-1559784094",
"creativeWidth": "980",
"creativeHeight": 240,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a valid scenario but you're not getting test coverage of lines if Herr != nil { and if len(adsErr) > 0 {. If you change this to a string that doesn't parse to an int (e.g. "ABC"), the call to ParseInt will return the error as Herr giving you the code coverage.

@mikael-lundin
Copy link
Contributor Author

mikael-lundin commented Oct 14, 2021 via email

@mikael-lundin
Copy link
Contributor Author

I think it was me doing something crazy when rebasing on your master. :) that's why you see double stuff, since that deleted file made it back again. Anyways, Hopefully I've done all the asked for things. Please do feel free to scold me if I missunderstood the last comment.

@bsardo
Copy link
Collaborator

bsardo commented Oct 14, 2021

The code looks good. We just need to clean up the commits here before merging. One way to do this is to create a new branch locally with a tip at PBS master:head and then cherry pick your commits from this branch onto it so your commits are sitting on top of master. Then force push your new branch to this PR effectively rewriting the commit history here. The PR should then only show your ~11 commits (we shouldn't need the merge commit mixed in there). Let me know if you have any questions.

@mikael-lundin mikael-lundin force-pushed the master branch 2 times, most recently from b21dd42 to 2f3b0b7 Compare October 15, 2021 10:03
@mikael-lundin
Copy link
Contributor Author

Let's hope I managed to do what you wrote! :D

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

Thanks for cleaning up the commits. I have just one last small comment.

}

if response.StatusCode != http.StatusOK {
return nil, []error{&errortypes.BadInput{
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you change this one to errortypes.BadServerResponse please? BadInput is typically reserved for invalid input but this catch all should typically handle other types of unexpected errors.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done and done!

@VeronikaSolovei9
Copy link
Contributor

Thank you for the updates, it looks good to me. I have a minor comment about errors return.

@mikael-lundin
Copy link
Contributor Author

mikael-lundin commented Oct 19, 2021 via email

bsardo
bsardo previously approved these changes Oct 19, 2021
Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

LGTM

if err != nil {
errs = append(errs, err...)
}
return extRequests, errs
Copy link
Contributor

Choose a reason for hiding this comment

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

This entire function can look like:

return a.generateRequests(*request)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

aah! much better! :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Thank you for addressing the comments :)


endpoint, err := makeEndpointUrl(ortbRequest, a)
if err != nil {
errors = append(errors, fmt.Errorf("failed to parse URL: %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.

Should it be return here instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it should, thanks! :D


if len(errors) > 0 {
return nil, errors
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Looks like it will be never more than one error in this list. Please consider to remove var errors []error and return error right after the occurrence.
Lines 189-191 can be removed, use Line 190 instead of 186

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for that, it makes much more sense


creativeHeight, heightErr := strconv.ParseInt(ad.CreativeHeight, 10, 64)
if heightErr != nil {
adsErr = append(adsErr, heightErr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need to collect errors here? (Lines 270 and 275)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no, I can just return them as I did above.

adDomain = append(adDomain, domain)
}

if len(adsErr) > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: Should you move it to Line 277?

@mansinahar
Copy link
Contributor

@mikael-lundin Just a friendly reminder about the comments above

@mikael-lundin
Copy link
Contributor Author

Thanks!! Will adress these

@mikael-lundin
Copy link
Contributor Author

Now, all the comments above should be fixed, sorry for missing them in the first place. :(

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

Looks good, just one last minor comment.

Comment on lines 120 to 122
return nil, []error{&errortypes.BadServerResponse{
Message: fmt.Sprintf("failed to parse URL: %s", err),
}}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think it would make more sense if this was BadInput since generating the URL endpoint involves unmarshaling various parts of the request (body or query string) and validating it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed! :D

Copy link
Collaborator

@bsardo bsardo left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@VeronikaSolovei9 VeronikaSolovei9 left a comment

Choose a reason for hiding this comment

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

LGTM

@bsardo bsardo merged commit 56e11d0 into prebid:master Oct 29, 2021
mansinahar pushed a commit to mansinahar/prebid-server that referenced this pull request Jan 18, 2022
jorgeluisrocha pushed a commit to jwplayer/prebid-server that referenced this pull request Sep 28, 2022
shunj-nb pushed a commit to ParticleMedia/prebid-server that referenced this pull request Nov 8, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants