Skip to content

Commit b5656a2

Browse files
Mohit TejaniMohit Tejani
authored andcommitted
added more tests to improve test coverage in SDK
1 parent 8e76683 commit b5656a2

File tree

7 files changed

+4291
-48
lines changed

7 files changed

+4291
-48
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ src/PNEventEngine/obj/*
184184
src/PNEventEngineUWP/bin/*
185185
src/PNEventEngineUWP/obj/*
186186

187+
CLAUDE.md
188+
.claude/*
189+
.cursor/*
190+
187191
# GitHub Actions #
188192
##################
189193
.github/.release

src/Api/PubnubApi/EndPoint/PubSub/SubscribeEndpoint.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,29 @@ private void MessageEmitter<T>(Pubnub pubnubInstance, PNMessageResult<T> message
216216
{
217217
foreach (var listener in SubscribeListenerList)
218218
{
219-
listener?.Message(pubnubInstance, messageResult);
219+
try
220+
{
221+
listener?.Message(pubnubInstance, messageResult);
222+
}
223+
catch (Exception ex)
224+
{
225+
config.Logger?.Error($"error during event handler function, {ex.Message}");
226+
}
220227
}
221228
}
222229

223230
private void StatusEmitter(Pubnub pubnubInstance, PNStatus status)
224231
{
225232
foreach (var listener in SubscribeListenerList)
226233
{
227-
listener?.Status(pubnubInstance, status);
234+
try
235+
{
236+
listener?.Status(pubnubInstance, status);
237+
}
238+
catch (Exception ex)
239+
{
240+
config.Logger?.Error($"error during event handler function, {ex.Message}");
241+
}
228242
}
229243
}
230244

src/Api/PubnubApi/EventEngine/Common/EventEmitter.cs

Lines changed: 54 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,32 @@ public EventEmitter(PNConfiguration configuration, List<SubscribeCallback> liste
3131
channelListenersMap = new Dictionary<string, List<SubscribeCallback>>();
3232
}
3333

34+
/// <summary>
35+
/// Safely invokes a listener callback with exception handling to prevent listener exceptions from affecting SDK operations.
36+
/// </summary>
37+
/// <param name="listenerAction">The listener callback action to invoke.</param>
38+
/// <param name="eventType">The type of event being processed (for logging purposes).</param>
39+
/// <remarks>
40+
/// This method ensures that exceptions thrown by user-provided listener callbacks do not crash the SDK
41+
/// or prevent other listeners from receiving events. All exceptions are logged at Warning level.
42+
/// </remarks>
43+
private void SafeInvokeListener(Action listenerAction, string eventType)
44+
{
45+
if (listenerAction == null)
46+
{
47+
return;
48+
}
49+
50+
try
51+
{
52+
listenerAction.Invoke();
53+
}
54+
catch (Exception ex)
55+
{
56+
configuration?.Logger?.Warn($"Exception in listener callback execution for {eventType}: {ex.Message}");
57+
}
58+
}
59+
3460
private TimetokenMetadata GetTimetokenMetadata(object t)
3561
{
3662
Dictionary<string, object> ttOriginMetaData = jsonLibrary.ConvertToDictionaryObject(t);
@@ -214,22 +240,22 @@ public void EmitEvent<T>(object e)
214240
};
215241
foreach (var listener in listeners)
216242
{
217-
listener?.Signal(instance, signalMessage);
243+
SafeInvokeListener(() => listener?.Signal(instance, signalMessage), "Signal");
218244
}
219245

220246
if (!string.IsNullOrEmpty(signalMessage.Channel) && channelListenersMap.ContainsKey(signalMessage.Channel))
221247
{
222248
foreach (var l in channelListenersMap[signalMessage.Channel])
223249
{
224-
l?.Signal(instance, signalMessage);
250+
SafeInvokeListener(() => l?.Signal(instance, signalMessage), "Signal");
225251
}
226252
}
227253

228254
if (!string.IsNullOrEmpty(signalMessage.Subscription) && channelGroupListenersMap.ContainsKey(signalMessage.Subscription))
229255
{
230256
foreach (var l in channelGroupListenersMap[signalMessage.Subscription])
231257
{
232-
l?.Signal(instance, signalMessage);
258+
SafeInvokeListener(() => l?.Signal(instance, signalMessage), "Signal");
233259
}
234260
}
235261
}
@@ -244,22 +270,22 @@ public void EmitEvent<T>(object e)
244270
{
245271
foreach (var listener in listeners)
246272
{
247-
listener?.ObjectEvent(instance, objectApiEvent);
273+
SafeInvokeListener(() => listener?.ObjectEvent(instance, objectApiEvent), "ObjectEvent");
248274
}
249275

250276
if (!string.IsNullOrEmpty(objectApiEvent.Channel) && channelListenersMap.ContainsKey(objectApiEvent.Channel))
251277
{
252278
foreach (var l in channelListenersMap[objectApiEvent.Channel])
253279
{
254-
l?.ObjectEvent(instance, objectApiEvent);
280+
SafeInvokeListener(() => l?.ObjectEvent(instance, objectApiEvent), "ObjectEvent");
255281
}
256282
}
257283

258284
if (!string.IsNullOrEmpty(objectApiEvent.Subscription) && channelGroupListenersMap.ContainsKey(objectApiEvent.Subscription))
259285
{
260286
foreach (var l in channelGroupListenersMap[objectApiEvent.Subscription])
261287
{
262-
l?.ObjectEvent(instance, objectApiEvent);
288+
SafeInvokeListener(() => l?.ObjectEvent(instance, objectApiEvent), "ObjectEvent");
263289
}
264290
}
265291
}
@@ -274,22 +300,22 @@ public void EmitEvent<T>(object e)
274300
{
275301
foreach (var listener in listeners)
276302
{
277-
listener?.MessageAction(instance, messageActionEvent);
303+
SafeInvokeListener(() => listener?.MessageAction(instance, messageActionEvent), "MessageAction");
278304
}
279305

280306
if (!string.IsNullOrEmpty(messageActionEvent.Channel) && channelListenersMap.ContainsKey(messageActionEvent.Channel))
281307
{
282308
foreach (var l in channelListenersMap[messageActionEvent.Channel])
283309
{
284-
l?.MessageAction(instance, messageActionEvent);
310+
SafeInvokeListener(() => l?.MessageAction(instance, messageActionEvent), "MessageAction");
285311
}
286312
}
287313

288314
if (!string.IsNullOrEmpty(messageActionEvent.Subscription) && channelGroupListenersMap.ContainsKey(messageActionEvent.Subscription))
289315
{
290316
foreach (var l in channelGroupListenersMap[messageActionEvent.Subscription])
291317
{
292-
l?.MessageAction(instance, messageActionEvent);
318+
SafeInvokeListener(() => l?.MessageAction(instance, messageActionEvent), "MessageAction");
293319
}
294320
}
295321
}
@@ -340,22 +366,22 @@ public void EmitEvent<T>(object e)
340366

341367
foreach (var listener in listeners)
342368
{
343-
listener?.File(instance, fileMessage);
369+
SafeInvokeListener(() => listener?.File(instance, fileMessage), "File");
344370
}
345371

346372
if (!string.IsNullOrEmpty(fileMessage.Channel) && channelListenersMap.ContainsKey(fileMessage.Channel))
347373
{
348374
foreach (var l in channelListenersMap[fileMessage.Channel])
349375
{
350-
l?.File(instance, fileMessage);
376+
SafeInvokeListener(() => l?.File(instance, fileMessage), "File");
351377
}
352378
}
353379

354380
if (!string.IsNullOrEmpty(fileMessage.Subscription) && channelGroupListenersMap.ContainsKey(fileMessage.Subscription))
355381
{
356382
foreach (var l in channelGroupListenersMap[fileMessage.Subscription])
357383
{
358-
l?.File(instance, fileMessage);
384+
SafeInvokeListener(() => l?.File(instance, fileMessage), "File");
359385
}
360386
}
361387
}
@@ -372,22 +398,22 @@ public void EmitEvent<T>(object e)
372398
{
373399
foreach (var listener in listeners)
374400
{
375-
listener?.Presence(instance, presenceEvent);
401+
SafeInvokeListener(() => listener?.Presence(instance, presenceEvent), "Presence");
376402
}
377403

378404
if (!string.IsNullOrEmpty(presenceEvent.Channel) && channelListenersMap.ContainsKey(presenceEvent.Channel))
379405
{
380406
foreach (var l in channelListenersMap[presenceEvent.Channel])
381407
{
382-
l?.Presence(instance, presenceEvent);
408+
SafeInvokeListener(() => l?.Presence(instance, presenceEvent), "Presence");
383409
}
384410
}
385411

386412
if (!string.IsNullOrEmpty(presenceEvent.Subscription) && channelGroupListenersMap.ContainsKey(presenceEvent.Subscription))
387413
{
388414
foreach (var l in channelGroupListenersMap[presenceEvent.Subscription])
389415
{
390-
l?.Presence(instance, presenceEvent);
416+
SafeInvokeListener(() => l?.Presence(instance, presenceEvent), "Presence");
391417
}
392418
}
393419
}
@@ -397,37 +423,29 @@ public void EmitEvent<T>(object e)
397423
jsonFields.Add("customMessageType", eventData.CustomMessageType);
398424
ResponseBuilder responseBuilder =new ResponseBuilder(configuration, jsonLibrary);
399425
PNMessageResult<T> userMessage = responseBuilder.GetEventResultObject<PNMessageResult<T>>(jsonFields);
400-
try
426+
if (userMessage != null)
401427
{
402-
if (userMessage != null)
428+
foreach (var listener in listeners)
403429
{
404-
foreach (var listener in listeners)
405-
{
406-
listener?.Message(instance, userMessage);
407-
}
430+
SafeInvokeListener(() => listener?.Message(instance, userMessage), "Message");
431+
}
408432

409-
if (!string.IsNullOrEmpty(userMessage.Channel) && channelListenersMap.ContainsKey(userMessage.Channel))
433+
if (!string.IsNullOrEmpty(userMessage.Channel) && channelListenersMap.ContainsKey(userMessage.Channel))
434+
{
435+
foreach (var l in channelListenersMap[userMessage.Channel])
410436
{
411-
foreach (var l in channelListenersMap[userMessage.Channel])
412-
{
413-
l?.Message(instance, userMessage);
414-
}
437+
SafeInvokeListener(() => l?.Message(instance, userMessage), "Message");
415438
}
439+
}
416440

417-
if (!string.IsNullOrEmpty(userMessage.Subscription) && channelGroupListenersMap.ContainsKey(userMessage.Subscription))
441+
if (!string.IsNullOrEmpty(userMessage.Subscription) && channelGroupListenersMap.ContainsKey(userMessage.Subscription))
442+
{
443+
foreach (var l in channelGroupListenersMap[userMessage.Subscription])
418444
{
419-
foreach (var l in channelGroupListenersMap[userMessage.Subscription])
420-
{
421-
l?.Message(instance, userMessage);
422-
}
445+
SafeInvokeListener(() => l?.Message(instance, userMessage), "Message");
423446
}
424447
}
425448
}
426-
catch (Exception ex)
427-
{
428-
configuration.Logger?.Error(
429-
$"Listener call back execution encounters error: {ex.Message}\n{ex?.StackTrace}");
430-
}
431449
}
432450

433451
break;

src/Api/PubnubApi/PubnubCoreBase.cs

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1886,10 +1886,17 @@ internal void Announce(PNStatus status)
18861886
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
18871887
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
18881888
{
1889-
callbackList[listenerIndex].Status(PubnubInstance, status);
1889+
try
1890+
{
1891+
callbackList[listenerIndex].Status(PubnubInstance, status);
1892+
}
1893+
catch (Exception ex)
1894+
{
1895+
logger?.Error($"error during event handler function, {ex.Message}");
1896+
}
18901897
}
18911898
}
1892-
1899+
18931900
}
18941901

18951902
internal void Announce<T>(PNMessageResult<T> message)
@@ -1899,7 +1906,14 @@ internal void Announce<T>(PNMessageResult<T> message)
18991906
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
19001907
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
19011908
{
1902-
callbackList[listenerIndex].Message(PubnubInstance, message);
1909+
try
1910+
{
1911+
callbackList[listenerIndex].Message(PubnubInstance, message);
1912+
}
1913+
catch (Exception ex)
1914+
{
1915+
logger?.Error($"error during event handler function, {ex.Message}");
1916+
}
19031917
}
19041918
}
19051919
}
@@ -1911,7 +1925,14 @@ internal void Announce<T>(PNSignalResult<T> message)
19111925
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
19121926
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
19131927
{
1914-
callbackList[listenerIndex].Signal(PubnubInstance, message);
1928+
try
1929+
{
1930+
callbackList[listenerIndex].Signal(PubnubInstance, message);
1931+
}
1932+
catch (Exception ex)
1933+
{
1934+
logger?.Error($"error during event handler function, {ex.Message}");
1935+
}
19151936
}
19161937
}
19171938
}
@@ -1923,7 +1944,14 @@ internal void Announce(PNFileEventResult message)
19231944
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
19241945
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
19251946
{
1926-
callbackList[listenerIndex].File(PubnubInstance, message);
1947+
try
1948+
{
1949+
callbackList[listenerIndex].File(PubnubInstance, message);
1950+
}
1951+
catch (Exception ex)
1952+
{
1953+
logger?.Error($"error during event handler function, {ex.Message}");
1954+
}
19271955
}
19281956
}
19291957
}
@@ -1935,7 +1963,14 @@ internal void Announce(PNPresenceEventResult presence)
19351963
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
19361964
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
19371965
{
1938-
callbackList[listenerIndex].Presence(PubnubInstance, presence);
1966+
try
1967+
{
1968+
callbackList[listenerIndex].Presence(PubnubInstance, presence);
1969+
}
1970+
catch (Exception ex)
1971+
{
1972+
logger?.Error($"error during event handler function, {ex.Message}");
1973+
}
19391974
}
19401975
}
19411976
}
@@ -1947,7 +1982,14 @@ internal void Announce(PNObjectEventResult objectApiEvent)
19471982
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
19481983
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
19491984
{
1950-
callbackList[listenerIndex].ObjectEvent(PubnubInstance, objectApiEvent);
1985+
try
1986+
{
1987+
callbackList[listenerIndex].ObjectEvent(PubnubInstance, objectApiEvent);
1988+
}
1989+
catch (Exception ex)
1990+
{
1991+
logger?.Error($"error during event handler function, {ex.Message}");
1992+
}
19511993
}
19521994
}
19531995
}
@@ -1959,7 +2001,14 @@ internal void Announce(PNMessageActionEventResult messageActionEvent)
19592001
List<SubscribeCallback> callbackList = SubscribeCallbackListenerList[PubnubInstance.InstanceId];
19602002
for (int listenerIndex = 0; listenerIndex < callbackList.Count; listenerIndex++)
19612003
{
1962-
callbackList[listenerIndex].MessageAction(PubnubInstance, messageActionEvent);
2004+
try
2005+
{
2006+
callbackList[listenerIndex].MessageAction(PubnubInstance, messageActionEvent);
2007+
}
2008+
catch (Exception ex)
2009+
{
2010+
logger?.Error($"error during event handler function, {ex.Message}");
2011+
}
19632012
}
19642013
}
19652014
}

0 commit comments

Comments
 (0)