Skip to content

Commit 0699b40

Browse files
authored
Add onEventTracked listener (#56)
1 parent 9fb24fa commit 0699b40

File tree

5 files changed

+102
-0
lines changed

5 files changed

+102
-0
lines changed

core-api/src/main/java/com/optimizely/ab/Optimizely.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ private void track(@Nonnull String eventName,
256256
} catch (Exception e) {
257257
logger.error("Unexpected exception in event dispatcher", e);
258258
}
259+
260+
notificationBroadcaster.broadcastEventTracked(eventName, userId, attributes, eventValue,
261+
conversionEvent);
259262
}
260263

261264
//======== live variable getters ========//

core-api/src/main/java/com/optimizely/ab/notification/NotificationBroadcaster.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
import com.optimizely.ab.annotations.VisibleForTesting;
1919
import com.optimizely.ab.config.Experiment;
2020
import com.optimizely.ab.config.Variation;
21+
import com.optimizely.ab.event.LogEvent;
2122

2223
import org.slf4j.Logger;
2324
import org.slf4j.LoggerFactory;
2425

2526
import java.util.HashSet;
2627
import java.util.Map;
2728

29+
import javax.annotation.CheckForNull;
2830
import javax.annotation.Nonnull;
2931

3032
/**
@@ -75,6 +77,25 @@ public void clearListeners() {
7577
logger.debug("Notification listeners were cleared");
7678
}
7779

80+
/**
81+
* Notify listeners that an Optimizely event has been tracked.
82+
*
83+
* @param eventKey the key of the tracked event
84+
* @param userId the ID of the user
85+
* @param attributes a map of attributes about the event
86+
* @param eventValue an integer to be aggregated for the event
87+
* @param logEvent the log event sent to the event dispatcher
88+
*/
89+
public void broadcastEventTracked(@Nonnull String eventKey,
90+
@Nonnull String userId,
91+
@Nonnull Map<String, String> attributes,
92+
@CheckForNull Long eventValue,
93+
@Nonnull LogEvent logEvent) {
94+
for (final NotificationListener iterListener : listeners) {
95+
iterListener.onEventTracked(eventKey, userId, attributes, eventValue, logEvent);
96+
}
97+
}
98+
7899
/**
79100
* Notify listeners that an Optimizely experiment has been activated.
80101
*

core-api/src/main/java/com/optimizely/ab/notification/NotificationListener.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818
import com.optimizely.ab.config.Experiment;
1919
import com.optimizely.ab.config.Variation;
20+
import com.optimizely.ab.event.LogEvent;
2021

2122
import java.util.Map;
2223

24+
import javax.annotation.CheckForNull;
2325
import javax.annotation.Nonnull;
2426

2527
/**
@@ -33,6 +35,22 @@
3335
*/
3436
public abstract class NotificationListener {
3537

38+
/**
39+
* Listener that is called after an event is tracked.
40+
*
41+
* @param eventKey the key of the tracked event
42+
* @param userId the ID of the user
43+
* @param attributes a map of attributes about the event
44+
* @param eventValue an integer to be aggregated for the event
45+
* @param logEvent the log event sent to the event dispatcher
46+
*/
47+
public void onEventTracked(@Nonnull String eventKey,
48+
@Nonnull String userId,
49+
@Nonnull Map<String, String> attributes,
50+
@CheckForNull Long eventValue,
51+
@Nonnull LogEvent logEvent) {
52+
}
53+
3654
/**
3755
* Listener that is called after an experiment has been activated.
3856
*

core-api/src/test/java/com/optimizely/ab/OptimizelyTestV3.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,19 @@ public void addNotificationListener() throws Exception {
15061506
optimizely.getVariableString("string_variable", userId, attributes, activateExperiment);
15071507
verify(listener, times(2))
15081508
.onExperimentActivated(activatedExperiment, userId, attributes, actualVariation);
1509+
1510+
// Check if listener is notified after an event is tracked
1511+
EventType eventType = projectConfig.getEventTypes().get(0);
1512+
String eventKey = eventType.getKey();
1513+
1514+
when(mockEventBuilder.createConversionEvent(eq(projectConfig), eq(mockBucketer), eq(userId),
1515+
eq(eventType.getId()), eq(eventKey),
1516+
anyMapOf(String.class, String.class)))
1517+
.thenReturn(logEventToDispatch);
1518+
1519+
optimizely.track(eventKey, userId, attributes);
1520+
verify(listener, times(1))
1521+
.onEventTracked(eventKey, userId, attributes, null, logEventToDispatch);
15091522
}
15101523

15111524
/**
@@ -1560,6 +1573,19 @@ public void removeNotificationListener() throws Exception {
15601573
optimizely.getVariableString("string_variable", userId, attributes, activateExperiment);
15611574
verify(listener, never())
15621575
.onExperimentActivated(activatedExperiment, userId, attributes, actualVariation);
1576+
1577+
// Check if listener is notified after an event is tracked
1578+
EventType eventType = projectConfig.getEventTypes().get(0);
1579+
String eventKey = eventType.getKey();
1580+
1581+
when(mockEventBuilder.createConversionEvent(eq(projectConfig), eq(mockBucketer), eq(userId),
1582+
eq(eventType.getId()), eq(eventKey),
1583+
anyMapOf(String.class, String.class)))
1584+
.thenReturn(logEventToDispatch);
1585+
1586+
optimizely.track(eventKey, userId, attributes);
1587+
verify(listener, never())
1588+
.onEventTracked(eventKey, userId, attributes, null, logEventToDispatch);
15631589
}
15641590

15651591
/**
@@ -1613,6 +1639,19 @@ public void clearNotificationListeners() throws Exception {
16131639
optimizely.getVariableString("string_variable", userId, attributes, activateExperiment);
16141640
verify(listener, never())
16151641
.onExperimentActivated(activatedExperiment, userId, attributes, actualVariation);
1642+
1643+
// Check if listener is notified after a event is tracked
1644+
EventType eventType = projectConfig.getEventTypes().get(0);
1645+
String eventKey = eventType.getKey();
1646+
1647+
when(mockEventBuilder.createConversionEvent(eq(projectConfig), eq(mockBucketer), eq(userId),
1648+
eq(eventType.getId()), eq(eventKey),
1649+
anyMapOf(String.class, String.class)))
1650+
.thenReturn(logEventToDispatch);
1651+
1652+
optimizely.track(eventKey, userId, attributes);
1653+
verify(listener, never())
1654+
.onEventTracked(eventKey, userId, attributes, null, logEventToDispatch);
16161655
}
16171656

16181657
//======== Helper methods ========//

core-api/src/test/java/com/optimizely/ab/notification/NotificationBroadcasterTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.optimizely.ab.config.Experiment;
1919
import com.optimizely.ab.config.Variation;
20+
import com.optimizely.ab.event.LogEvent;
2021

2122
import org.junit.Before;
2223
import org.junit.Test;
@@ -103,6 +104,26 @@ public void clearListeners() throws Exception {
103104
0, notificationBroadcaster.listeners.size());
104105
}
105106

107+
/**
108+
* Verify that {@link NotificationBroadcaster#broadcastEventTracked(String, String, Map, Long, LogEvent)}
109+
* notifies all listeners.
110+
*/
111+
@Test
112+
public void broadcastEventTracked() throws Exception {
113+
notificationBroadcaster.addListener(listener);
114+
notificationBroadcaster.addListener(listener2);
115+
116+
String eventKey = "event1";
117+
String userId = "user1";
118+
Map<String, String> attributes = Collections.emptyMap();
119+
Long eventValue = 0L;
120+
LogEvent logEvent = mock(LogEvent.class);
121+
notificationBroadcaster.broadcastEventTracked(
122+
eventKey, userId, attributes, eventValue, logEvent);
123+
verify(listener).onEventTracked(eventKey, userId, attributes, eventValue, logEvent);
124+
verify(listener2).onEventTracked(eventKey, userId, attributes, eventValue, logEvent);
125+
}
126+
106127
/**
107128
* Verify that {@link NotificationBroadcaster#broadcastExperimentActivated(Experiment, String, Map, Variation)}
108129
* notifies all listeners.

0 commit comments

Comments
 (0)