Skip to content

Conversation

@msohailhussain
Copy link
Contributor

When track is called, onTrack should be used to notify user if definition for onTrack is set in the client.

@msohailhussain msohailhussain changed the title feat(onTrack): Added onTrack callback feat(onTrack): Added onTrack callback - DO NOT REVIEW Nov 26, 2019
@msohailhussain msohailhussain changed the title feat(onTrack): Added onTrack callback - DO NOT REVIEW feat(onTrack): Added onTrack callback Nov 27, 2019
@msohailhussain msohailhussain marked this pull request as ready for review November 27, 2019 18:19
@msohailhussain msohailhussain requested a review from a team as a code owner November 27, 2019 18:19
Copy link
Contributor

@mikeproeng37 mikeproeng37 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 the PR. There are two main issues I see:

  1. We should be able to attach more than 1 callback for track notifications

  2. 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

@msohailhussain
Copy link
Contributor Author

Sure, let me revise. I will discuss with you first.

Copy link
Contributor

@mikeproeng37 mikeproeng37 left a 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

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)
Copy link
Contributor

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

}
handler := func(payload interface{}) {
success := false
if trackPayload, ok := payload.([]interface{}); ok {
Copy link
Contributor

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

@msohailhussain
Copy link
Contributor Author

discussed offline, keeping it on hold. TrackNotification will have cyclic import issue if UserEvent is added there.

Copy link
Contributor

@mikeproeng37 mikeproeng37 left a 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

return "1.0.0"
}

func TestAddandRemoveOnTrack(t *testing.T) {
Copy link
Contributor

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

s.Equal(*s.mockProcessor.Events[0].Conversion, conversionEvent)
}

client := OptimizelyClient{
Copy link
Contributor

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

DecisionService: s.mockDecisionService,
EventProcessor: s.mockProcessor,
}
client.OnTrack(onTrack)
Copy link
Contributor

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.

}

mockNotificationCenter := new(MockNotificationCenter)
mockNotificationCenter.On("Send", mock.Anything, mock.Anything).Return(fmt.Errorf(""))
Copy link
Contributor

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

func (s *ClientTestSuiteTrackNotification) TestOnTrackThrowsErrorWhenAddHandlerFails() {

mockNotificationCenter := new(MockNotificationCenter)
mockNotificationCenter.On("AddHandler", mock.Anything, mock.Anything).Return(-1, fmt.Errorf(""))
Copy link
Contributor

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

func (s *ClientTestSuiteTrackNotification) TestRemoveOnTrackThrowsErrorWhenRemoveHandlerFails() {

mockNotificationCenter := new(MockNotificationCenter)
mockNotificationCenter.On("AddHandler", mock.Anything, mock.Anything).Return(1, nil)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

}

appClient := &OptimizelyClient{executionCtx: executionCtx}
appClient.NotificationCenter = registry.GetNotificationCenter(f.SDKKey)
Copy link
Contributor

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


func (s *ClientTestSuiteTrackEvent) TestTrackWithNotification() {

s.mockProcessor.On("ProcessEvent", mock.Anything).Return(true)
Copy link
Contributor Author

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.

s.Equal(*s.mockProcessor.Events[0].Conversion, conversionEvent)
}

s.client.OnTrack(onTrack)
Copy link
Contributor Author

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.


func (s *ClientTestSuiteTrackEvent) TestTrackWithNotificationAndEventTag() {

s.mockProcessor.On("ProcessEvent", mock.Anything).Return(true)
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.

}

func (s *ClientTestSuiteTrackEvent) TestTrackNotificationNotCalledWhenEventProcessorReturnsFalse() {
s.mockProcessor.On("ProcessEvent", mock.Anything).Return(false)
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 and do it in all other places.

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))
Copy link
Contributor Author

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{}{})
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 confusing, what's invalid here. Please add comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

Updated the test name.

}
}

func (s *ClientTestSuiteTrackNotification) TestAddandRemoveOnTrack() {
Copy link
Contributor Author

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() {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

separate into two tests.

@msohailhussain
Copy link
Contributor Author

LGTM.

Copy link
Contributor

@mikeproeng37 mikeproeng37 left a comment

Choose a reason for hiding this comment

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

lgtm

@mikeproeng37 mikeproeng37 merged commit f5b8ffe into master Dec 6, 2019
@mikeproeng37 mikeproeng37 deleted the sohail/ontrack branch December 6, 2019 21:54
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