-
Notifications
You must be signed in to change notification settings - Fork 766
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
Move user syncs to each respective adapter directory #688
Conversation
63d48d9
to
fb011e2
Compare
internal/testutil/usersync.go
Outdated
} | ||
|
||
// Assert common values match. | ||
func (u *usersyncTest) Assert(url, syncType string, vendor uint16, supportCORS bool) { |
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.
Maybe separate each value out into their own method like AssertFamilyName
"github.com/prebid/prebid-server/usersync" | ||
) | ||
|
||
func NewPubmaticSyncer(cfg *config.Configuration) usersync.Usersyncer { |
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.
Another way to do this function is to have a signature like:
func NewPubmaticSyncer(externalURL string, adapter config.Adapter) usersync.Usersyncer
which would avoid the need for some adapters to do a lookup on the adapter map.
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.
I'd also give a small edge to NewPubmaticSyncer(externalURL string, adapter config.Adapter)
, for the same reason you mentioned... but would accept a PR with either choice.
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.
I think the main reason I kept it that way was in case there were other configuration additions. I say we keep it for now and change it later if it makes sense.
internal/testutil/usersync.go
Outdated
@@ -0,0 +1,44 @@ | |||
package testutil |
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.
I don't like the idea of a "testutil" package...however, it's in the internal directory which is not exposed to the public api.
Thoughts?
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.
I'm a fan of code sharing. In the vast majority of cases, utils are much better than duplicate code.
I'm not too worried about the package API, either, because this is an application and not a library. Our REST APIs are very important... but the package APIs are less so because we don't expect people to use this code by importing it. Any package structure within this project is purely for our own sanity.
That said: if you take a step back, do you think these utilities really improve things? Compare these code snippets (loosely based on the sovrn
syncer).
Without utils (using testify):
info := syncer.GetUsersyncInfo("0", "")
assert.Equal(t, "//ap.lijit.com/pixel?redir=external.com%2Fsetuid%3Fbidder%3Dsovrn%26gdpr%3D0%26gdpr_consent%3D%26uid%3D%24UID", info.URL)
assert.Equal(t, "redirect", info.Type)
assert.False(t, info.SupportCORS)
assert.Equal(t, 13, syncer.GDPRVendorID())
With utils:
u := testutil.UsersyncTest(t, syncer, syncer.GetUsersyncInfo("0", ""))
u.Assert(
"//ap.lijit.com/pixel?redir=external.com%2Fsetuid%3Fbidder%3Dsovrn%26gdpr%3D0%26gdpr_consent%3D%26uid%3D%24UID",
"redirect",
13,
false,
)
Advantages of no utils:
- Fewer lines of code
- Clearer to read
- No need to implement the utils function
- No need to find a good package location for the utils implementation
Advantages of utils:
- When a field gets added to the usersyncer, we'd update
u.Assert
and nobody's tests would compile until every adapter is running the assertion
IMO it doesn't seem like the utils do enough to justify their existence... but let me know if I'm missing something.
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.
I was mostly avoiding adding another dependency, didn't realize testify was already being used so I will update it.
One quick comment about your statement:
I'm not too worried about the package API, either, because this is an application and not a library.
Treating the components as libraries and stabilizing the API will allow the community to use the code here and contribute back improvements. Keeping it isolated as an application will cause users to fork and less likely to contribute anything back (I know I sound like a broken record at this point, however I really feel like this will improve the health of the project).
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.
That's an interesting perspective... I wouldn't have thought this would make it hard for people to contribute to the project.
You're not a broken record at all. From your previous comments, I thought your main issue was that you or someone you knew was trying to add a Bidder and finding it annoying to change lots of different places in the code. I didn't realize you planned to import some packages and rely on them directly. Thanks for the perspective.
I do agree that the healthier an application architecture is, the more it resembles a bunch of libraries with a thin layer tying them all together... so whether or not we ultimately fold package APIs into our "v1" compatibility, it's definitely helpful to organize the code as if we plan to.
5a18782
to
544500b
Compare
Hey @zachbadgett... this still looks like a work-in-progress to me, but let me know if I'm mistaken and you're waiting on a review for it. Or re-edit the title to remove the |
eacd396
to
1862d05
Compare
@dbemiller this is done unless you have any other changes/comments. |
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.
yep yep, thanks!
Overall the structure is totally sensible. I do see a few issues too though.
} | ||
func TestNewSyncerMap(t *testing.T) { | ||
cfg := &config.Configuration{ | ||
Adapters: map[string]config.Adapter{ |
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.
Could you use the openrtb_ext.BidderMap
populate this?
I have an overarching goal: when someone tries to contribute an adapter, make it "impossible" to do wrong. Whenever possible, that means relying on the compiler & types. When types aren't enough possible, rely on the automated tests & CI.
The main value of TestSyncers
was to make sure that every Bidder in the project also had a Usersyncer. By defining the constants separately here, that's no longer enforced.
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.
In an effort to isolate adapters entirely I was thinking of doing something like this: zachbadgett@57a580c#diff-25c7c8df3a616bd75098f16d158d0a0bR29
This could still achieve your goal of "impossible" to do wrong by doing a panic on Register
.
The usersync/usersyncers/
would ultimately be removed.
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.
Keep in mind the design decisions I made in that commit attempts to change other code as little as possible (especially in the adapters themselves).
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.
yeah, that's fair.
I'm trying to make sure that the code is left in a good state after each PR. Someone might try to submit a Bidder between now and the time the next PR merges, or the next PR might never come.
We might also spend a while discussing tradeoffs. For init
& Register
in particular, I know we'll have at least some back and forth. I'm most definitely not an experienced Gopher... but I can think of some good language-agnostic reasons to avoid that structure, and the benefits that I can think of don't outweigh the costs. As an avid Go supporter, I'm curious to learn about how you weigh them :).
That's a long-winded way of saying: if the future changes don't pan out, I'd rather not lose the value provided by this test.
adapters/syncer_test.go
Outdated
|
||
func TestSyncers(t *testing.T) { | ||
syncers := make(map[openrtb_ext.BidderName]usersync.Usersyncer) | ||
for _, bidderName := range map[string]openrtb_ext.BidderName{} { |
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.
Dead test? This ranges over an empty map.
This may be related to the TestSyncerMap()
comment I made elsewhere. Looks like it may have gotten moved, changed a bit, and forgotten about?
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.
Not forgotten about, see my comment above. The map is ultimately moved to the adapters package, however importing the static map from where it lives now would cause a circular dependency.
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.
aha, yeah that makes sense. I wasn't sure which one of the two tests you wanted to be the "real" one.
Can you either move the static map into this package, or just delete this test? It doesn't make much sense to have a test without assertions.
adapters/syncer_test.go
Outdated
func TestVendorIDUniqueness(t *testing.T) { | ||
syncers := make(map[openrtb_ext.BidderName]usersync.Usersyncer) | ||
idMap := make(map[uint16]openrtb_ext.BidderName, 0) | ||
for name, syncer := range syncers { |
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.
Same thing here... range over an empty map.
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.
Given the circular dependency issue: could you either move this test back into the usersyncers
package for now, or else move the static map into this package to avoid the circular dependency?
Until the Register
/panic
changes are in, this test does have some value... and I have a few good reasons not to go that route, so I'd rather treat this PR as an isolated change set while we discuss.
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.
Sure thing!
@@ -0,0 +1,23 @@ | |||
// +build go1.11 |
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.
Can you split this Go 1.11 fix off into a separate PR? It's a valuable change... but commits do get squashed on merge, and it's unrelated.
Small note: I'd prefer something like message_go1.11
rather than message_alt
. We already know that this bug has been fixed in Go 1.11.1 (see golang/go#27275), so... it's a pretty specific fix.
Would also be nice to lin this issue somewhere in the file so we remember why the workaround exists.
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.
I was thinking the same thing for the message name. I went with message_alt because it will apply to go1.11+, now that I know it was an actual bug and it's been fix it makes a lot more sense to do message_go1.11.
0020e2d
to
93754f7
Compare
Looks like some of David's comments haven't been addressed yet? Are there still changes in the works, or is the current state what you think the final state should be? |
This is the final state, I fixed what he commented on. I'll resolve the conflicts today. |
oh! Sorry. I didn't know you were waiting on me here. Open issues I see are these:
Goals are:
Also: merge conflicts. |
93754f7
to
70b3d9a
Compare
Heh...I moved the tests but didn't commit the reverting of them. My mistake! Should be fixed now. |
adapters/syncer_test.go
Outdated
@@ -0,0 +1 @@ | |||
package adapters |
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.
Got an empty file here too... not sure if I only just noticed this now, or it became empty in those last changes.
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.
That's where those usersync tests were...and will be again eventually, not a big deal to delete for now.
* Move user syncs to each respective adapter directory Add internal/testutil package * Update usersync tests to use testify's assert * Update syncer tests * Add ix and rhythmone usersyncs * Remove syncer_test.go
* Move user syncs to each respective adapter directory Add internal/testutil package * Update usersync tests to use testify's assert * Update syncer tests * Add ix and rhythmone usersyncs * Remove syncer_test.go
* Move user syncs to each respective adapter directory Add internal/testutil package * Update usersync tests to use testify's assert * Update syncer tests * Add ix and rhythmone usersyncs * Remove syncer_test.go
Continued progress on adapter isolation.
Code complete and unit tests updated, still need to build and run it.