Skip to content

Commit 4ba497e

Browse files
authored
Merge branch 'master' into yasir/datafilerevisionlog
2 parents 4c4acba + 90b15a6 commit 4ba497e

File tree

8 files changed

+119
-14
lines changed

8 files changed

+119
-14
lines changed

optimizely/client/client_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,11 @@ func (m *PanickingDecisionService) GetFeatureDecision(decisionContext decision.F
9292
panic("I'm panicking")
9393
}
9494

95-
func (m *PanickingDecisionService) OnDecision(callback func(notification.DecisionNotification)) {
95+
func (m *PanickingDecisionService) OnDecision(callback func(notification.DecisionNotification)) (int, error) {
96+
panic("I'm panicking")
97+
}
98+
99+
func (m *PanickingDecisionService) RemoveOnDecision(id int) error {
96100
panic("I'm panicking")
97101
}
98102

optimizely/decision/composite_service.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,27 @@ func (s CompositeService) GetFeatureDecision(featureDecisionContext FeatureDecis
8888
}
8989

9090
// OnDecision registers a handler for Decision notifications
91-
func (s CompositeService) OnDecision(callback func(notification.DecisionNotification)) {
91+
func (s CompositeService) OnDecision(callback func(notification.DecisionNotification)) (int, error) {
9292
handler := func(payload interface{}) {
9393
if decisionNotification, ok := payload.(notification.DecisionNotification); ok {
9494
callback(decisionNotification)
9595
} else {
9696
csLogger.Warning(fmt.Sprintf("Unable to convert notification payload %v into DecisionNotification", payload))
9797
}
9898
}
99-
if _, err := s.notificationCenter.AddHandler(notification.Decision, handler); err != nil {
99+
id, err := s.notificationCenter.AddHandler(notification.Decision, handler)
100+
if err != nil {
100101
csLogger.Warning("Problem with adding notification handler")
102+
return 0, err
101103
}
104+
return id, nil
105+
}
106+
107+
// RemoveOnDecision removes handler for Decision notification with given id
108+
func (s CompositeService) RemoveOnDecision(id int) error {
109+
if err := s.notificationCenter.RemoveHandler(id, notification.Decision); err != nil {
110+
csLogger.Warning("Problem with removing notification handler")
111+
return err
112+
}
113+
return nil
102114
}

optimizely/decision/composite_service_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/stretchr/testify/assert"
2323

2424
"github.com/optimizely/go-sdk/optimizely/entities"
25+
"github.com/optimizely/go-sdk/optimizely/notification"
2526
)
2627

2728
func TestGetFeatureDecision(t *testing.T) {
@@ -54,3 +55,45 @@ func TestGetFeatureDecision(t *testing.T) {
5455
assert.Equal(t, expectedFeatureDecision, featureDecision)
5556
testFeatureDecisionService.AssertExpectations(t)
5657
}
58+
59+
func TestOnDecision(t *testing.T) {
60+
61+
mockProjectConfig := new(mockProjectConfig)
62+
decisionContext := FeatureDecisionContext{
63+
Feature: &testFeat3333,
64+
ProjectConfig: mockProjectConfig,
65+
}
66+
67+
userContext := entities.UserContext{
68+
ID: "test_user",
69+
}
70+
71+
expectedFeatureDecision := FeatureDecision{
72+
Experiment: testExp1111,
73+
Variation: &testExp1111Var2222,
74+
}
75+
76+
testFeatureDecisionService := new(MockFeatureDecisionService)
77+
testFeatureDecisionService.On("GetDecision", decisionContext, userContext).Return(expectedFeatureDecision, nil)
78+
79+
notificationCenter := notification.NewNotificationCenter()
80+
decisionService := &CompositeService{
81+
featureDecisionServices: []FeatureService{testFeatureDecisionService},
82+
notificationCenter: notificationCenter,
83+
}
84+
85+
var numberOfCalls = 0
86+
callback := func(notification notification.DecisionNotification) {
87+
numberOfCalls++
88+
}
89+
id, _ := decisionService.OnDecision(callback)
90+
91+
assert.NotEqual(t, id, 0)
92+
decisionService.GetFeatureDecision(decisionContext, userContext)
93+
assert.Equal(t, numberOfCalls, 1)
94+
95+
err := decisionService.RemoveOnDecision(id)
96+
assert.Nil(t, err)
97+
decisionService.GetFeatureDecision(decisionContext, userContext)
98+
assert.Equal(t, numberOfCalls, 1)
99+
}

optimizely/decision/interface.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import (
2525
// Service interface is used to make a decision for a given feature or experiment
2626
type Service interface {
2727
GetFeatureDecision(FeatureDecisionContext, entities.UserContext) (FeatureDecision, error)
28-
OnDecision(func(notification.DecisionNotification))
28+
OnDecision(func(notification.DecisionNotification)) (int, error)
29+
RemoveOnDecision(id int) error
2930
}
3031

3132
// ExperimentService can make a decision about an experiment

optimizely/notification/center.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import "fmt"
2222
// Center handles all notification listeners. It keeps track of the Manager for each type of notification.
2323
type Center interface {
2424
AddHandler(Type, func(interface{})) (int, error)
25+
RemoveHandler(int, Type) error
2526
Send(Type, interface{}) error
2627
}
2728

@@ -43,12 +44,22 @@ func NewNotificationCenter() *DefaultCenter {
4344
// AddHandler adds a handler for the given notification type
4445
func (c *DefaultCenter) AddHandler(notificationType Type, handler func(interface{})) (int, error) {
4546
if manager, ok := c.managerMap[notificationType]; ok {
46-
return manager.AddHandler(handler)
47+
return manager.Add(handler)
4748
}
4849

4950
return -1, fmt.Errorf("no notification manager found for type %s", notificationType)
5051
}
5152

53+
// RemoveHandler removes a handler for the given id and notification type
54+
func (c *DefaultCenter) RemoveHandler(id int, notificationType Type) error {
55+
if manager, ok := c.managerMap[notificationType]; ok {
56+
manager.Remove(id)
57+
return nil
58+
}
59+
60+
return fmt.Errorf("no notification manager found for type %s", notificationType)
61+
}
62+
5263
// Send sends the given notification payload to all listeners of type
5364
func (c *DefaultCenter) Send(notificationType Type, notification interface{}) error {
5465
if manager, ok := c.managerMap[notificationType]; ok {

optimizely/notification/center_test.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package notification
33
import (
44
"testing"
55

6+
"github.com/stretchr/testify/assert"
7+
68
"github.com/optimizely/go-sdk/optimizely/entities"
79
"github.com/stretchr/testify/mock"
810
)
@@ -32,10 +34,24 @@ func TestNotificationCenter(t *testing.T) {
3234
mockReceiver.On("handleNotification", testDecisionNotification)
3335
mockReceiver2.On("handleNotification", testDecisionNotification)
3436
notificationCenter := NewNotificationCenter()
35-
notificationCenter.AddHandler(Decision, mockReceiver.handleNotification)
36-
notificationCenter.AddHandler(Decision, mockReceiver2.handleNotification)
37+
id1, err1 := notificationCenter.AddHandler(Decision, mockReceiver.handleNotification)
38+
id2, err2 := notificationCenter.AddHandler(Decision, mockReceiver2.handleNotification)
3739
notificationCenter.Send(Decision, testDecisionNotification)
3840

3941
mockReceiver.AssertExpectations(t)
4042
mockReceiver2.AssertExpectations(t)
43+
assert.Nil(t, err1)
44+
assert.Nil(t, err2)
45+
46+
notificationCenter.RemoveHandler(id1, Decision)
47+
notificationCenter.Send(Decision, testDecisionNotification)
48+
49+
mockReceiver.AssertNumberOfCalls(t, "handleNotification", 1)
50+
mockReceiver2.AssertNumberOfCalls(t, "handleNotification", 2)
51+
52+
notificationCenter.RemoveHandler(id2, Decision)
53+
notificationCenter.Send(Decision, testDecisionNotification)
54+
55+
mockReceiver.AssertNumberOfCalls(t, "handleNotification", 1)
56+
mockReceiver2.AssertNumberOfCalls(t, "handleNotification", 2)
4157
}

optimizely/notification/manager.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import (
2323

2424
// Manager is a generic interface for managing notifications of a particular type
2525
type Manager interface {
26-
AddHandler(func(interface{})) (int, error)
26+
Add(func(interface{})) (int, error)
27+
Remove(id int)
2728
Send(message interface{})
2829
}
2930

@@ -40,13 +41,21 @@ func NewAtomicManager() *AtomicManager {
4041
}
4142
}
4243

43-
// AddHandler adds the given handler
44-
func (am *AtomicManager) AddHandler(newHandler func(interface{})) (int, error) {
44+
// Add adds the given handler
45+
func (am *AtomicManager) Add(newHandler func(interface{})) (int, error) {
4546
atomic.AddUint32(&am.counter, 1)
4647
am.handlers[am.counter] = newHandler
4748
return int(am.counter), nil
4849
}
4950

51+
// Remove removes handler with the given id
52+
func (am *AtomicManager) Remove(id int) {
53+
handlerID := uint32(id)
54+
if _, ok := am.handlers[handlerID]; ok {
55+
delete(am.handlers, handlerID)
56+
}
57+
}
58+
5059
// Send sends the notification to the registered handlers
5160
func (am *AtomicManager) Send(notification interface{}) {
5261
for _, handler := range am.handlers {

optimizely/notification/manager_test.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,21 @@ func TestAtomicManager(t *testing.T) {
2929
mockReceiver.On("handleBetter", payload)
3030

3131
atomicManager := NewAtomicManager()
32-
result, _ := atomicManager.AddHandler(mockReceiver.handle)
33-
assert.Equal(t, 1, result)
32+
result1, _ := atomicManager.Add(mockReceiver.handle)
33+
assert.Equal(t, 1, result1)
3434

35-
result, _ = atomicManager.AddHandler(mockReceiver.handleBetter)
36-
assert.Equal(t, 2, result)
35+
result2, _ := atomicManager.Add(mockReceiver.handleBetter)
36+
assert.Equal(t, 2, result2)
3737

3838
atomicManager.Send(payload)
3939
mockReceiver.AssertExpectations(t)
40+
41+
atomicManager.Remove(result1)
42+
atomicManager.Send(payload)
43+
mockReceiver.AssertNumberOfCalls(t, "handle", 1)
44+
mockReceiver.AssertNumberOfCalls(t, "handleBetter", 2)
45+
46+
atomicManager.Remove(result2)
47+
atomicManager.Send(payload)
48+
mockReceiver.AssertNumberOfCalls(t, "handleBetter", 2)
4049
}

0 commit comments

Comments
 (0)