Skip to content

Commit a41e960

Browse files
mfahadahmedMichael Ng
authored andcommitted
feat(notification-center): Adds LogEvent notification (#188)
1 parent c47d7e7 commit a41e960

File tree

5 files changed

+88
-6
lines changed

5 files changed

+88
-6
lines changed

OptimizelySDK.Tests/EventTests/BatchEventProcessorTest.cs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class BatchEventProcessorTest
3030
private BatchEventProcessor EventProcessor;
3131
private Mock<IEventDispatcher> EventDispatcherMock;
3232
private TestEventDispatcher TestEventDispatcher;
33+
private NotificationCenter NotificationCenter = new NotificationCenter();
34+
private Mock<TestNotificationCallbacks> NotificationCallbackMock;
3335

3436
[SetUp]
3537
public void Setup()
@@ -41,6 +43,12 @@ public void Setup()
4143

4244
eventQueue = new BlockingCollection<object>(100);
4345
EventDispatcherMock = new Mock<IEventDispatcher>();
46+
47+
NotificationCallbackMock = new Mock<TestNotificationCallbacks>();
48+
NotificationCallbackMock.Setup(nc => nc.TestLogEventCallback(It.IsAny<LogEvent>()));
49+
50+
NotificationCenter.AddNotification(NotificationCenter.NotificationType.LogEvent,
51+
NotificationCallbackMock.Object.TestLogEventCallback);
4452
}
4553

4654
[TearDown]
@@ -202,7 +210,21 @@ public void TestStopAndStart()
202210

203211
Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification.");
204212
}
205-
213+
214+
[Test]
215+
public void TestNotificationCenter()
216+
{
217+
var countdownEvent = new CountdownEvent(1);
218+
NotificationCenter.AddNotification(NotificationCenter.NotificationType.LogEvent, logEvent => countdownEvent.Signal());
219+
SetEventProcessor(EventDispatcherMock.Object);
220+
221+
UserEvent userEvent = BuildConversionEvent(EventName);
222+
EventProcessor.Process(userEvent);
223+
224+
EventProcessor.Stop();
225+
Assert.True(countdownEvent.Wait(TimeSpan.FromMilliseconds(MAX_DURATION_MS * 3)), "Exceeded timeout waiting for notification.");
226+
}
227+
206228
[Test]
207229
public void TestCloseTimeout()
208230
{
@@ -226,6 +248,7 @@ private void SetEventProcessor(IEventDispatcher eventDispatcher)
226248
.WithFlushInterval(TimeSpan.FromMilliseconds(MAX_DURATION_MS))
227249
.WithTimeoutInterval(TimeSpan.FromMilliseconds(TIMEOUT_INTERVAL_MS))
228250
.WithLogger(LoggerMock.Object)
251+
.WithNotificationCenter(NotificationCenter)
229252
.Build();
230253
}
231254

OptimizelySDK.Tests/EventTests/CanonicalEvent.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class CanonicalEvent
1111
private string VariationId;
1212
private string EventName;
1313
private string VisitorId;
14+
1415
private UserAttributes Attributes;
1516
private EventTags Tags;
1617

@@ -20,6 +21,7 @@ public CanonicalEvent(string experimentId, string variationId, string eventName,
2021
VariationId = variationId;
2122
EventName = eventName;
2223
VisitorId = visitorId;
24+
2325
Attributes = attributes ?? new UserAttributes();
2426
Tags = tags ?? new EventTags();
2527
}

OptimizelySDK.Tests/NotificationTests/NotificationCenterTests.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ public void TestAddMultipleNotificationListeners()
8282
// Verify that notifications of other types will also gets added successfully.
8383
NotificationCenter.AddNotification(NotificationType.OptimizelyConfigUpdate, TestNotificationCallbacks.TestConfigUpdateCallback);
8484
Assert.AreEqual(4, NotificationCenter.NotificationsCount);
85+
86+
// Verify that notifications of other types will also gets added successfully.
87+
NotificationCenter.AddNotification(NotificationType.LogEvent, TestNotificationCallbacks.TestLogEventCallback);
88+
Assert.AreEqual(5, NotificationCenter.NotificationsCount);
8589
}
8690

8791
[Test]
@@ -179,12 +183,12 @@ public void TestSendNotifications()
179183
notificationCallbackMock.Setup(nc => nc.TestAnotherActivateCallback(It.IsAny<Experiment>(),
180184
It.IsAny<string>(), It.IsAny<UserAttributes>(), It.IsAny<Variation>(), It.IsAny<LogEvent>()));
181185

186+
notificationCallbackMock.Setup(nc => nc.TestLogEventCallback(It.IsAny<LogEvent>()));
182187

183188
// Adding decision notifications.
184189
NotificationCenter.AddNotification(NotificationTypeActivate, notificationCallbackMock.Object.TestActivateCallback);
185190
NotificationCenter.AddNotification(NotificationTypeActivate, notificationCallbackMock.Object.TestAnotherActivateCallback);
186191

187-
188192
// Adding track notifications.
189193
NotificationCenter.AddNotification(NotificationTypeTrack, notificationCallbackMock.Object.TestTrackCallback);
190194

@@ -202,8 +206,14 @@ public void TestSendNotifications()
202206
notificationCallbackMock.Verify(nc => nc.TestTrackCallback(It.IsAny<string>(), It.IsAny<string>(),
203207
It.IsAny<UserAttributes>(), It.IsAny<EventTags>(), It.IsAny<LogEvent>()), Times.Never);
204208

209+
// Add logEvent Notification.
210+
NotificationCenter.AddNotification(NotificationType.LogEvent, notificationCallbackMock.Object.TestLogEventCallback);
205211

212+
// Fire logEvent Notification.
213+
NotificationCenter.SendNotifications(NotificationType.LogEvent, logEventMocker.Object);
206214

215+
// Verify that registered notifications of logEvent type are called.
216+
notificationCallbackMock.Verify(nc => nc.TestLogEventCallback(It.IsAny<LogEvent>()), Times.Once);
207217

208218
// Verify that after clearing notifications, SendNotification should not call any notification
209219
// which were previously registered.
@@ -253,7 +263,12 @@ public virtual void TestAnotherTrackCallback(string eventKey, string userId, Use
253263
public virtual void TestDecisionCallback(string type, string userId, UserAttributes userAttributes,
254264
Dictionary<string, object> decisionInfo) {
255265
}
256-
public virtual void TestConfigUpdateCallback() { }
266+
267+
public virtual void TestConfigUpdateCallback() {
268+
}
269+
270+
public virtual void TestLogEventCallback(LogEvent logEvent) {
271+
}
257272
}
258273
#endregion // Test Notification callbacks class.
259274
}

OptimizelySDK/Event/BatchEventProcessor.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using OptimizelySDK.ErrorHandler;
2525
using System.Linq;
2626
using OptimizelySDK.Event.Dispatcher;
27+
using OptimizelySDK.Notifications;
2728

2829
namespace OptimizelySDK.Event
2930
{
@@ -56,6 +57,7 @@ public class BatchEventProcessor: EventProcessor, IDisposable
5657

5758
protected ILogger Logger { get; set; }
5859
protected IErrorHandler ErrorHandler { get; set; }
60+
public NotificationCenter NotificationCenter { get; set; }
5961

6062
private readonly object mutex = new object();
6163

@@ -155,7 +157,9 @@ private void FlushQueue()
155157

156158

157159
LogEvent logEvent = EventFactory.CreateLogEvent(toProcessBatch.ToArray(), Logger);
158-
160+
161+
NotificationCenter?.SendNotifications(NotificationCenter.NotificationType.LogEvent, logEvent);
162+
159163
try
160164
{
161165
EventDispatcher?.DispatchEvent(logEvent);
@@ -259,6 +263,7 @@ public class Builder
259263
private TimeSpan? TimeoutInterval;
260264
private IErrorHandler ErrorHandler;
261265
private ILogger Logger;
266+
private NotificationCenter NotificationCenter;
262267

263268
public Builder WithEventQueue(BlockingCollection<object> eventQueue)
264269
{
@@ -302,6 +307,13 @@ public Builder WithLogger(ILogger logger = null)
302307
return this;
303308
}
304309

310+
public Builder WithNotificationCenter(NotificationCenter notificationCenter)
311+
{
312+
NotificationCenter = notificationCenter;
313+
314+
return this;
315+
}
316+
305317
public Builder WithTimeoutInterval(TimeSpan timeout)
306318
{
307319
TimeoutInterval = timeout;
@@ -330,7 +342,8 @@ public BatchEventProcessor Build(bool start)
330342
batchEventProcessor.ErrorHandler = ErrorHandler;
331343
batchEventProcessor.EventDispatcher = EventDispatcher;
332344
batchEventProcessor.EventQueue = EventQueue;
333-
345+
batchEventProcessor.NotificationCenter = NotificationCenter;
346+
334347
batchEventProcessor.BatchSize = BatchSize ?? BatchEventProcessor.DEFAULT_BATCH_SIZE;
335348
batchEventProcessor.FlushInterval = FlushInterval ?? BatchEventProcessor.DEFAULT_FLUSH_INTERVAL;
336349
batchEventProcessor.TimeoutInterval = TimeoutInterval ?? BatchEventProcessor.DEFAULT_TIMEOUT_INTERVAL;

OptimizelySDK/Notifications/NotificationCenter.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public enum NotificationType
3636
Activate, // Activate called.
3737
Track, // Track called.
3838
Decision, // A decision is made in the system. i.e. user activation, feature access or feature-variable value retrieval.
39-
OptimizelyConfigUpdate // When datafile is updated using HttpProjectConfigManager.
39+
OptimizelyConfigUpdate, // When datafile is updated using HttpProjectConfigManager.
40+
LogEvent // LogEvent notification sends on flushing batch-event. // When datafile is updated using HttpProjectConfigManager.
4041
};
4142

4243
/// <summary>
@@ -76,6 +77,12 @@ public delegate void TrackCallback(string eventKey, string userId, UserAttribute
7677
/// </summary>
7778
public delegate void OptimizelyConfigUpdateCallback();
7879

80+
/// <summary>
81+
/// Delegate for batch-event flushing.
82+
/// </summary>
83+
/// <param name="logEvent">The log event</param>
84+
public delegate void LogEventCallback(LogEvent logEvent);
85+
7986
private ILogger Logger;
8087

8188
// Notification Id represeting number of notifications.
@@ -158,6 +165,13 @@ public int AddNotification(NotificationType notificationType, DecisionCallback d
158165
return AddNotification(notificationType, (object)decisionCallback);
159166
}
160167

168+
/// <summary>
169+
/// Add a notification callback of config-update type to the notification center.
170+
/// </summary>
171+
/// <param name="notificationType">Notification type</param>
172+
/// <param name="optimizelyConfigUpdate">Callback function to call when event gets triggered</param>
173+
/// <returns>0 for invalid notification type, -1 for adding existing notification
174+
/// or the notification id of newly added notification.</returns>
161175
public int AddNotification(NotificationType notificationType, OptimizelyConfigUpdateCallback optimizelyConfigUpdate)
162176
{
163177
if (!IsNotificationTypeValid(notificationType, NotificationType.OptimizelyConfigUpdate))
@@ -166,6 +180,21 @@ public int AddNotification(NotificationType notificationType, OptimizelyConfigUp
166180
return AddNotification(notificationType, (object)optimizelyConfigUpdate);
167181
}
168182

183+
/// <summary>
184+
/// Add a notification callback of logEvent type to the notification center.
185+
/// </summary>
186+
/// <param name="notificationType">Notification type</param>
187+
/// <param name="logEventCallback">Callback function to call when event gets triggered</param>
188+
/// <returns>0 for invalid notification type, -1 for adding existing notification
189+
/// or the notification id of newly added notification.</returns>
190+
public int AddNotification(NotificationType notificationType, LogEventCallback logEventCallback)
191+
{
192+
if (!IsNotificationTypeValid(notificationType, NotificationType.LogEvent))
193+
return 0;
194+
195+
return AddNotification(notificationType, (object)logEventCallback);
196+
}
197+
169198
/// <summary>
170199
/// Validate notification type.
171200
/// </summary>

0 commit comments

Comments
 (0)