-
Notifications
You must be signed in to change notification settings - Fork 19
feat(onTrack): Added onTrack callback #198
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
Conversation
mikeproeng37
left a comment
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.
Thanks for the PR. There are two main issues I see:
-
We should be able to attach more than 1 callback for track notifications
-
I still think we should go through the notification center so that other components in the SDK could subscribe to this notification if they wanted to. This also helps streamline how we do notifications throughout the SDK
|
Sure, let me revise. I will discuss with you first. |
mikeproeng37
left a comment
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.
Please fix test coverage as well
pkg/client/client.go
Outdated
| if o.EventProcessor.ProcessEvent(userEvent) && o.NotificationCenter != nil { | ||
| trackNotification := notification.TrackNotification{Type: notification.Track, EventKey: eventKey, UserContext: userContext, EventTags: eventTags} | ||
| var payload []interface{} | ||
| payload = append(payload, trackNotification, userEvent) |
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.
Why make this an array? We can add the UserEvent to the track notification struct
pkg/client/client.go
Outdated
| } | ||
| handler := func(payload interface{}) { | ||
| success := false | ||
| if trackPayload, ok := payload.([]interface{}); ok { |
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.
Should be casting to a TrackNotification directly
|
discussed offline, keeping it on hold. TrackNotification will have cyclic import issue if |
mikeproeng37
left a comment
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.
Mostly good, just need to redo the unit tests
pkg/client/client_test.go
Outdated
| return "1.0.0" | ||
| } | ||
|
|
||
| func TestAddandRemoveOnTrack(t *testing.T) { |
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 create a test suite for these new tests to have better code reuse?
We already have some test suites towards the end like this:
func TestClientTestSuite(t *testing.T) {
suite.Run(t, new(ClientTestSuiteAB))
suite.Run(t, new(ClientTestSuiteFM))
}
So you can add 1 test suite for the notifications APIs and another one for event tracking for the tests you added further below. Don't worry about refactoring the current track tests, you can simply add the track notification track tests in the test suite
pkg/client/client_test.go
Outdated
| s.Equal(*s.mockProcessor.Events[0].Conversion, conversionEvent) | ||
| } | ||
|
|
||
| client := OptimizelyClient{ |
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 client initialization is repeated throughout the tests in the suite. We can initialize in the test setup
pkg/client/client_test.go
Outdated
| DecisionService: s.mockDecisionService, | ||
| EventProcessor: s.mockProcessor, | ||
| } | ||
| client.OnTrack(onTrack) |
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 is incorrect, we need to populate the notification center to ensure that there was nothing router through it.
pkg/client/client_test.go
Outdated
| } | ||
|
|
||
| mockNotificationCenter := new(MockNotificationCenter) | ||
| mockNotificationCenter.On("Send", mock.Anything, mock.Anything).Return(fmt.Errorf("")) |
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.
Let's not accept anything. We should correctly type the arguments received in the send method. We don't have to do it for AddHandler below we cannot compare functions. HOwever we should at least ensure that the argument is of type func
pkg/client/client_test.go
Outdated
| func (s *ClientTestSuiteTrackNotification) TestOnTrackThrowsErrorWhenAddHandlerFails() { | ||
|
|
||
| mockNotificationCenter := new(MockNotificationCenter) | ||
| mockNotificationCenter.On("AddHandler", mock.Anything, mock.Anything).Return(-1, fmt.Errorf("")) |
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.
Assert the type, don't use mock.Anything
pkg/client/client_test.go
Outdated
| func (s *ClientTestSuiteTrackNotification) TestRemoveOnTrackThrowsErrorWhenRemoveHandlerFails() { | ||
|
|
||
| mockNotificationCenter := new(MockNotificationCenter) | ||
| mockNotificationCenter.On("AddHandler", mock.Anything, mock.Anything).Return(1, nil) |
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 as above.
pkg/client/factory.go
Outdated
| } | ||
|
|
||
| appClient := &OptimizelyClient{executionCtx: executionCtx} | ||
| appClient.NotificationCenter = registry.GetNotificationCenter(f.SDKKey) |
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 doesn't need to be set after the object init. You can put it right after the exec context
pkg/client/client_test.go
Outdated
|
|
||
| func (s *ClientTestSuiteTrackEvent) TestTrackWithNotification() { | ||
|
|
||
| s.mockProcessor.On("ProcessEvent", mock.Anything).Return(true) |
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.
mock.Anything is very general. We are using ConversionEvent, so please use that type.
pkg/client/client_test.go
Outdated
| s.Equal(*s.mockProcessor.Events[0].Conversion, conversionEvent) | ||
| } | ||
|
|
||
| s.client.OnTrack(onTrack) |
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.
add return ID and assert that.
pkg/client/client_test.go
Outdated
|
|
||
| func (s *ClientTestSuiteTrackEvent) TestTrackWithNotificationAndEventTag() { | ||
|
|
||
| s.mockProcessor.On("ProcessEvent", mock.Anything).Return(true) |
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 as above.
pkg/client/client_test.go
Outdated
| } | ||
|
|
||
| func (s *ClientTestSuiteTrackEvent) TestTrackNotificationNotCalledWhenEventProcessorReturnsFalse() { | ||
| s.mockProcessor.On("ProcessEvent", mock.Anything).Return(false) |
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 as above and do it in all other places.
pkg/client/client_test.go
Outdated
| err := s.client.Track("sample_conversion", entities.UserContext{ID: "1212121", Attributes: map[string]interface{}{}}, map[string]interface{}{}) | ||
|
|
||
| s.NoError(err) | ||
| s.Equal(1, len(s.mockProcessor.Events)) |
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.
How it can be 1. I think this is confusing. The best way would be to mock event.CreateConversionEvent if possible. and return any invalid type and let ProcessEvent do its job. It will return error while invalid type is passed.
| } | ||
|
|
||
| s.client.OnTrack(onTrack) | ||
| err := s.client.Track("bob", entities.UserContext{ID: "1212121", Attributes: map[string]interface{}{}}, map[string]interface{}{}) |
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 is confusing, what's invalid here. Please add comment.
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.
Updated the test name.
pkg/client/client_test.go
Outdated
| } | ||
| } | ||
|
|
||
| func (s *ClientTestSuiteTrackNotification) TestAddandRemoveOnTrack() { |
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.
Please break down this test into 2 or 3 tests.
- Add multiple ontrack and assert
- Add multiple ontrack, remove by ID and assert then.
- Add, remove, add and assert.
Make sure, IDs are always increased(unique).
| s.Equal(0, numberOfCalls) | ||
| } | ||
|
|
||
| func (s *ClientTestSuiteTrackNotification) TestOnTrackThrowsErrorWithoutNotificationCenter() { |
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.
separate into two tests.
|
LGTM. |
mikeproeng37
left a comment
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.
lgtm
When track is called, onTrack should be used to notify user if definition for onTrack is set in the client.