From c82ea143b987621994bcfb752402e81a2c832947 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 4 Dec 2025 13:45:35 -0800 Subject: [PATCH 01/87] add models --- src/Splitio/Domain/EventMetadata.cs | 52 ++++++++++++++++ src/Splitio/Domain/SdkEvent.cs | 9 +++ src/Splitio/Domain/SdkInternalEvent.cs | 12 ++++ src/Splitio/Services/Common/ISdkEventTask.cs | 15 +++++ .../Classes/PropertiesValidator.cs | 2 +- .../Unit Tests/Common/EventMetadataTests.cs | 61 +++++++++++++++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/Splitio/Domain/EventMetadata.cs create mode 100644 src/Splitio/Domain/SdkEvent.cs create mode 100644 src/Splitio/Domain/SdkInternalEvent.cs create mode 100644 src/Splitio/Services/Common/ISdkEventTask.cs create mode 100644 tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs diff --git a/src/Splitio/Domain/EventMetadata.cs b/src/Splitio/Domain/EventMetadata.cs new file mode 100644 index 00000000..7847c670 --- /dev/null +++ b/src/Splitio/Domain/EventMetadata.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using Splitio.Services.InputValidation.Classes; +using System.Linq; + +namespace Splitio.Domain +{ + public class EventMetadata + { + private Dictionary _data; + + public EventMetadata(Dictionary data) + { + _data = Santize(data); + } + + public Dictionary GetData() { return _data; } + + public List GetKeys() { return _data.Keys.ToList(); } + + public List GetValues() { return _data.Values.ToList(); } + + public bool ContainKey(string key) + { + return _data.ContainsKey(key); + } + + private Dictionary Santize(Dictionary data) + { + Dictionary santizedData = new Dictionary(); + foreach (var item in data) + { + if (ValueIsValid(item.Value)) + { + santizedData.Add(item.Key, item.Value); + } + } + + return santizedData; + } + + private bool ValueIsValid(object value) + { + if (!(value is null) && (PropertiesValidator.IsNumeric(value) || (value is bool) || (value is string) || (value is List))) + { + return true; + } + + return false; + } + + } +} diff --git a/src/Splitio/Domain/SdkEvent.cs b/src/Splitio/Domain/SdkEvent.cs new file mode 100644 index 00000000..b11effa6 --- /dev/null +++ b/src/Splitio/Domain/SdkEvent.cs @@ -0,0 +1,9 @@ + +namespace Splitio.Domain +{ + public enum SdkEvent + { + SdkUpdate, + SdkReadyTimeout + } +} diff --git a/src/Splitio/Domain/SdkInternalEvent.cs b/src/Splitio/Domain/SdkInternalEvent.cs new file mode 100644 index 00000000..2650577e --- /dev/null +++ b/src/Splitio/Domain/SdkInternalEvent.cs @@ -0,0 +1,12 @@ + +namespace Splitio.Domain +{ + public enum SdkInternalEvent + { + FlagsUpdated, + FlagKilledNotification, + RuleBasedSegmentsUpdated, + SegmentsUpdated, + LargeSegmentsUpdated + } +} diff --git a/src/Splitio/Services/Common/ISdkEventTask.cs b/src/Splitio/Services/Common/ISdkEventTask.cs new file mode 100644 index 00000000..e2c48145 --- /dev/null +++ b/src/Splitio/Services/Common/ISdkEventTask.cs @@ -0,0 +1,15 @@ +using Splitio.Domain; +using Splitio.Services.Client.Classes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Splitio.Services.Common +{ + public interface ISdkEventTask + { + Task OnExecute(SplitClient splitClient, EventMetadata eventMetadata); + } +} diff --git a/src/Splitio/Services/InputValidation/Classes/PropertiesValidator.cs b/src/Splitio/Services/InputValidation/Classes/PropertiesValidator.cs index e1e7a29f..2c47febb 100644 --- a/src/Splitio/Services/InputValidation/Classes/PropertiesValidator.cs +++ b/src/Splitio/Services/InputValidation/Classes/PropertiesValidator.cs @@ -62,7 +62,7 @@ public PropertiesValidatorResult IsValid(Dictionary properties) }; } - private static bool IsNumeric(object value) + public static bool IsNumeric(object value) { if (value == null) return false; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs new file mode 100644 index 00000000..dfcba68b --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs @@ -0,0 +1,61 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using Splitio.Domain; + +namespace Splitio_Tests.Unit_Tests.Common +{ + [TestClass] + public class EventMetadataTests + { + + [TestMethod] + public void InstanceWithSantizeInput() + { + //Arrange + Dictionary data = new Dictionary + { + { "updatedFlags", new List() { { "feature1" } } }, + { "sdkTimeout", 10 }, + { "boolValue", true }, + { "strValue", "value" } + }; + + //Act + var result = new EventMetadata(data); + + //Assert + Assert.AreEqual(4, result.GetKeys().Count); + result.GetData().TryGetValue("updatedFlags", out var features); + List featureList = (List)features; + result.GetData().TryGetValue("sdkTimeout", out var timeout); + result.GetData().TryGetValue("boolValue", out var bvalue); + result.GetData().TryGetValue("strValue", out var svalue); + + Assert.AreEqual(10, timeout); + Assert.AreEqual(true, bvalue); + Assert.AreEqual("value", svalue); + Assert.IsTrue(featureList.Count == 1); + Assert.IsTrue(featureList.Contains("feature1")); + Assert.IsTrue(result.ContainKey("updatedFlags")); + } + + [TestMethod] + public void SantizeNullInput() + { + //Arrange + Dictionary data = new Dictionary + { + { "wrong-null", null }, + { "wrong-other", new List() }, + { "updatedFlags", new List() { { "feature1" } } } + }; + + //Act + var result = new EventMetadata(data); + + //Assert + Assert.AreEqual(1, result.GetKeys().Count); + Assert.IsTrue(result.ContainKey("updatedFlags")); + } + } +} From c6983d4a0364e54c44b474c3cd65a9e0629604a5 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Thu, 4 Dec 2025 19:44:45 -0800 Subject: [PATCH 02/87] Update SdkInternalEvent.cs --- src/Splitio/Domain/SdkInternalEvent.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Splitio/Domain/SdkInternalEvent.cs b/src/Splitio/Domain/SdkInternalEvent.cs index 2650577e..651d0cf2 100644 --- a/src/Splitio/Domain/SdkInternalEvent.cs +++ b/src/Splitio/Domain/SdkInternalEvent.cs @@ -7,6 +7,8 @@ public enum SdkInternalEvent FlagKilledNotification, RuleBasedSegmentsUpdated, SegmentsUpdated, - LargeSegmentsUpdated + LargeSegmentsUpdated, + SdkTimedOut, + SdkReady } } From cb26c84b27c535054921f5947630663f6b612efa Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 5 Dec 2025 10:59:49 -0800 Subject: [PATCH 03/87] added events manager config --- src/Splitio/Domain/EventsManagerConfig.cs | 64 +++++++++++++++++++ .../Common/EventsManagerConfigTests.cs | 34 ++++++++++ 2 files changed, 98 insertions(+) create mode 100644 src/Splitio/Domain/EventsManagerConfig.cs create mode 100644 tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs new file mode 100644 index 00000000..b8015425 --- /dev/null +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; + +namespace Splitio.Domain +{ + public class EventsManagerConfig + { + public Dictionary> RequireAll { get; private set; } + public Dictionary> RequireAny { get; private set; } + public Dictionary> Prerequisites { get; private set; } + public Dictionary> SuppressedBy { get; private set; } + public Dictionary ExecutionLimits { get; private set; } + + private EventsManagerConfig( + Dictionary> requireAll, + Dictionary> requireAny, + Dictionary> prerequisites, + Dictionary> suppressedBy, + Dictionary executionLimits) + { + RequireAll = requireAll; + RequireAny = requireAny; + Prerequisites = prerequisites; + SuppressedBy = suppressedBy; + ExecutionLimits = executionLimits; + } + + public static EventsManagerConfig BuildEventsManagerConfig() + { + Dictionary> requireAll = new Dictionary>(); + Dictionary> prerequisites = new Dictionary>(); + Dictionary> requireAny = new Dictionary> + { + { SdkEvent.SdkUpdate, new HashSet + { + SdkInternalEvent.RuleBasedSegmentsUpdated, + SdkInternalEvent.FlagsUpdated, + SdkInternalEvent.FlagKilledNotification, + SdkInternalEvent.LargeSegmentsUpdated, + SdkInternalEvent.SegmentsUpdated + } + }, + { SdkEvent.SdkReadyTimeout, new HashSet + { + SdkInternalEvent.SdkTimedOut + } + } + }; + Dictionary> suppressedBy = new Dictionary> + { + { SdkEvent.SdkReadyTimeout, new HashSet + { SdkInternalEvent.SdkReady } + + } + }; + Dictionary executionLimits = new Dictionary + { + { SdkEvent.SdkReadyTimeout, 1 }, + { SdkEvent.SdkUpdate, -1 } + }; + + return new EventsManagerConfig(requireAll, requireAny, prerequisites, suppressedBy, executionLimits); + } + } +} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs new file mode 100644 index 00000000..70d449ad --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -0,0 +1,34 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Splitio.Domain; + +namespace Splitio_Tests.Unit_Tests.Common +{ + [TestClass] + public class EventsManagerConfigTests + { + + [TestMethod] + public void BuildInstance() + { + //Act + EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + + //Assert + config.ExecutionLimits.TryGetValue(SdkEvent.SdkReadyTimeout, out var timout); + Assert.AreEqual(1, timout); + config.ExecutionLimits.TryGetValue(SdkEvent.SdkUpdate, out var update); + Assert.AreEqual(-1, update); + + config.RequireAny.TryGetValue(SdkEvent.SdkReadyTimeout, out var require1); + Assert.AreEqual(1, require1.Count); + Assert.IsTrue(require1.Contains(SdkInternalEvent.SdkTimedOut)); + config.RequireAny.TryGetValue(SdkEvent.SdkUpdate, out var require2); + Assert.AreEqual(5, require2.Count); + Assert.IsTrue(require2.Contains(SdkInternalEvent.SegmentsUpdated)); + Assert.IsTrue(require2.Contains(SdkInternalEvent.LargeSegmentsUpdated)); + Assert.IsTrue(require2.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); + Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagKilledNotification)); + Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagsUpdated)); + } + } +} From 4b27df37a6cd24cc096159c33f46c5c253bf4236 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 5 Dec 2025 13:25:06 -0800 Subject: [PATCH 04/87] Added sdk ready event --- src/Splitio/Domain/EventsManagerConfig.cs | 40 ++++++++++++++----- src/Splitio/Domain/SdkEvent.cs | 3 +- .../Common/EventsManagerConfigTests.cs | 18 +++++++-- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index b8015425..00fd7076 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -24,24 +24,43 @@ private EventsManagerConfig( ExecutionLimits = executionLimits; } - public static EventsManagerConfig BuildEventsManagerConfig() + public static EventsManagerConfig BuildEventsManagerConfig() { - Dictionary> requireAll = new Dictionary>(); - Dictionary> prerequisites = new Dictionary>(); + Dictionary> requireAll = new Dictionary> + { + { + SdkEvent.SdkReady, new HashSet + { + SdkInternalEvent.RuleBasedSegmentsUpdated, + SdkInternalEvent.FlagsUpdated, + SdkInternalEvent.LargeSegmentsUpdated, + SdkInternalEvent.SegmentsUpdated + } + } + }; + Dictionary> prerequisites = new Dictionary> + { + { + SdkEvent.SdkUpdate, new HashSet + { + SdkInternalEvent.SdkReady + } + } + }; Dictionary> requireAny = new Dictionary> { { SdkEvent.SdkUpdate, new HashSet { - SdkInternalEvent.RuleBasedSegmentsUpdated, - SdkInternalEvent.FlagsUpdated, - SdkInternalEvent.FlagKilledNotification, - SdkInternalEvent.LargeSegmentsUpdated, - SdkInternalEvent.SegmentsUpdated + SdkInternalEvent.RuleBasedSegmentsUpdated, + SdkInternalEvent.FlagsUpdated, + SdkInternalEvent.FlagKilledNotification, + SdkInternalEvent.LargeSegmentsUpdated, + SdkInternalEvent.SegmentsUpdated } }, - { SdkEvent.SdkReadyTimeout, new HashSet + { SdkEvent.SdkReadyTimeout, new HashSet { - SdkInternalEvent.SdkTimedOut + SdkInternalEvent.SdkTimedOut } } }; @@ -55,6 +74,7 @@ public static EventsManagerConfig BuildEventsManagerConfig() Dictionary executionLimits = new Dictionary { { SdkEvent.SdkReadyTimeout, 1 }, + { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; diff --git a/src/Splitio/Domain/SdkEvent.cs b/src/Splitio/Domain/SdkEvent.cs index b11effa6..5c8fbe70 100644 --- a/src/Splitio/Domain/SdkEvent.cs +++ b/src/Splitio/Domain/SdkEvent.cs @@ -4,6 +4,7 @@ namespace Splitio.Domain public enum SdkEvent { SdkUpdate, - SdkReadyTimeout + SdkReadyTimeout, + SdkReady } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index 70d449ad..f9618b46 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -14,14 +14,26 @@ public void BuildInstance() EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); //Assert + config.RequireAll.TryGetValue(SdkEvent.SdkReady, out var require1); + Assert.AreEqual(4, require1.Count); + Assert.IsTrue(require1.Contains(SdkInternalEvent.SegmentsUpdated)); + Assert.IsTrue(require1.Contains(SdkInternalEvent.LargeSegmentsUpdated)); + Assert.IsTrue(require1.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); + Assert.IsTrue(require1.Contains(SdkInternalEvent.FlagsUpdated)); + + config.Prerequisites.TryGetValue(SdkEvent.SdkUpdate, out var ready2); + Assert.IsTrue(ready2.Contains(SdkInternalEvent.SdkReady)); + config.ExecutionLimits.TryGetValue(SdkEvent.SdkReadyTimeout, out var timout); Assert.AreEqual(1, timout); config.ExecutionLimits.TryGetValue(SdkEvent.SdkUpdate, out var update); Assert.AreEqual(-1, update); + config.ExecutionLimits.TryGetValue(SdkEvent.SdkReady, out var ready); + Assert.AreEqual(1, ready); - config.RequireAny.TryGetValue(SdkEvent.SdkReadyTimeout, out var require1); - Assert.AreEqual(1, require1.Count); - Assert.IsTrue(require1.Contains(SdkInternalEvent.SdkTimedOut)); + config.RequireAny.TryGetValue(SdkEvent.SdkReadyTimeout, out var require3); + Assert.AreEqual(1, require3.Count); + Assert.IsTrue(require3.Contains(SdkInternalEvent.SdkTimedOut)); config.RequireAny.TryGetValue(SdkEvent.SdkUpdate, out var require2); Assert.AreEqual(5, require2.Count); Assert.IsTrue(require2.Contains(SdkInternalEvent.SegmentsUpdated)); From 8a617427bc6bcdec80012e04e2ff09b869735e49 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 5 Dec 2025 13:46:19 -0800 Subject: [PATCH 05/87] removed large segment from config --- src/Splitio/Domain/EventsManagerConfig.cs | 2 -- .../Unit Tests/Common/EventsManagerConfigTests.cs | 6 ++---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 00fd7076..3146baa9 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -33,7 +33,6 @@ public static EventsManagerConfig BuildEventsManagerConfig() { SdkInternalEvent.RuleBasedSegmentsUpdated, SdkInternalEvent.FlagsUpdated, - SdkInternalEvent.LargeSegmentsUpdated, SdkInternalEvent.SegmentsUpdated } } @@ -54,7 +53,6 @@ public static EventsManagerConfig BuildEventsManagerConfig() SdkInternalEvent.RuleBasedSegmentsUpdated, SdkInternalEvent.FlagsUpdated, SdkInternalEvent.FlagKilledNotification, - SdkInternalEvent.LargeSegmentsUpdated, SdkInternalEvent.SegmentsUpdated } }, diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index f9618b46..e65ae86b 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -15,9 +15,8 @@ public void BuildInstance() //Assert config.RequireAll.TryGetValue(SdkEvent.SdkReady, out var require1); - Assert.AreEqual(4, require1.Count); + Assert.AreEqual(3, require1.Count); Assert.IsTrue(require1.Contains(SdkInternalEvent.SegmentsUpdated)); - Assert.IsTrue(require1.Contains(SdkInternalEvent.LargeSegmentsUpdated)); Assert.IsTrue(require1.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); Assert.IsTrue(require1.Contains(SdkInternalEvent.FlagsUpdated)); @@ -35,9 +34,8 @@ public void BuildInstance() Assert.AreEqual(1, require3.Count); Assert.IsTrue(require3.Contains(SdkInternalEvent.SdkTimedOut)); config.RequireAny.TryGetValue(SdkEvent.SdkUpdate, out var require2); - Assert.AreEqual(5, require2.Count); + Assert.AreEqual(4, require2.Count); Assert.IsTrue(require2.Contains(SdkInternalEvent.SegmentsUpdated)); - Assert.IsTrue(require2.Contains(SdkInternalEvent.LargeSegmentsUpdated)); Assert.IsTrue(require2.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagKilledNotification)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagsUpdated)); From 3571825721e1d3314aaab18a8595ba8bce6577e3 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 8 Dec 2025 13:32:57 -0800 Subject: [PATCH 06/87] initial draft - events manager and supporting classes --- src/Splitio/Domain/EventsManagerConfig.cs | 42 +++- src/Splitio/Domain/SdkEvent.cs | 3 +- src/Splitio/Services/Common/EventDelivery.cs | 16 ++ src/Splitio/Services/Common/EventHandler.cs | 181 ++++++++++++++++++ src/Splitio/Services/Common/EventsManager.cs | 106 ++++++++++ src/Splitio/Services/Common/IEventDelivery.cs | 9 + src/Splitio/Services/Common/IEventHandler.cs | 9 + src/Splitio/Services/Common/IEventsManager.cs | 14 ++ .../Common/EventsManagerConfigTests.cs | 20 +- 9 files changed, 384 insertions(+), 16 deletions(-) create mode 100644 src/Splitio/Services/Common/EventDelivery.cs create mode 100644 src/Splitio/Services/Common/EventHandler.cs create mode 100644 src/Splitio/Services/Common/EventsManager.cs create mode 100644 src/Splitio/Services/Common/IEventDelivery.cs create mode 100644 src/Splitio/Services/Common/IEventHandler.cs create mode 100644 src/Splitio/Services/Common/IEventsManager.cs diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index b8015425..c260f113 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -24,27 +24,47 @@ private EventsManagerConfig( ExecutionLimits = executionLimits; } - public static EventsManagerConfig BuildEventsManagerConfig() + public static EventsManagerConfig BuildEventsManagerConfig() { - Dictionary> requireAll = new Dictionary>(); - Dictionary> prerequisites = new Dictionary>(); + Dictionary> requireAll = new Dictionary> + { + { + SdkEvent.SdkReady, new HashSet + { + SdkInternalEvent.RuleBasedSegmentsUpdated, + SdkInternalEvent.FlagsUpdated, + SdkInternalEvent.SegmentsUpdated + } + } + }; + + Dictionary> prerequisites = new Dictionary> + { + { + SdkEvent.SdkUpdate, new HashSet + { + SdkInternalEvent.SdkReady + } + } + }; + Dictionary> requireAny = new Dictionary> { { SdkEvent.SdkUpdate, new HashSet { - SdkInternalEvent.RuleBasedSegmentsUpdated, - SdkInternalEvent.FlagsUpdated, - SdkInternalEvent.FlagKilledNotification, - SdkInternalEvent.LargeSegmentsUpdated, - SdkInternalEvent.SegmentsUpdated + SdkInternalEvent.RuleBasedSegmentsUpdated, + SdkInternalEvent.FlagsUpdated, + SdkInternalEvent.FlagKilledNotification, + SdkInternalEvent.SegmentsUpdated } }, - { SdkEvent.SdkReadyTimeout, new HashSet + { SdkEvent.SdkReadyTimeout, new HashSet { - SdkInternalEvent.SdkTimedOut + SdkInternalEvent.SdkTimedOut } } }; + Dictionary> suppressedBy = new Dictionary> { { SdkEvent.SdkReadyTimeout, new HashSet @@ -52,9 +72,11 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; + Dictionary executionLimits = new Dictionary { { SdkEvent.SdkReadyTimeout, 1 }, + { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; diff --git a/src/Splitio/Domain/SdkEvent.cs b/src/Splitio/Domain/SdkEvent.cs index b11effa6..5c8fbe70 100644 --- a/src/Splitio/Domain/SdkEvent.cs +++ b/src/Splitio/Domain/SdkEvent.cs @@ -4,6 +4,7 @@ namespace Splitio.Domain public enum SdkEvent { SdkUpdate, - SdkReadyTimeout + SdkReadyTimeout, + SdkReady } } diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs new file mode 100644 index 00000000..ce1f2a06 --- /dev/null +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -0,0 +1,16 @@ +using Splitio.Domain; +using System; + +namespace Splitio.Services.Common +{ + public class EventDelivery : IEventDelivery + { + EventsManagerConfig _config; + EventsManager _eventsManager; + + + public void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata) + { } + + } +} diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs new file mode 100644 index 00000000..4661f045 --- /dev/null +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -0,0 +1,181 @@ +using Splitio.Domain; +using System.Collections.Generic; + +namespace Splitio.Services.Common +{ + public class EventHandler : IEventHandler + { + EventsManagerConfig _config; + EventsManager _eventsManager; + EventDelivery _eventDelivery; + struct ValidSdkEvent + { + public SdkEvent sdkEvent; + public bool valid; + } + + public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager, EventDelivery eventDelivery) + { + _config = eventsManagerConfig; + _eventsManager = eventsManager; + _eventDelivery = eventDelivery; + + _eventsManager.RuleBasedSegmentsUpdatedHandler += EventManager_RuleBasedSegmentsUpdatedHandler; + _eventsManager.FlagKilledNotificationHandler += EventManager_FlagKilledNotificationHandler; + _eventsManager.FlagsUpdatedHandler += EventManager_FlagsUpdatedHandler; + _eventsManager.SegmentsUpdatedHandler += EventManager_SegmentsUpdatedHandler; + _eventsManager.SdkReadyHandler += EventManager_SdkReadyHandler; + _eventsManager.SdkTimedOutHandler += EventManager_SdkTimedOutHandler; + } + + public void Handle(SdkEvent sdkEvent, EventMetadata eventMetadata) + { + _eventDelivery.Deliver(sdkEvent, eventMetadata); + } + + void HandleInternalEvent(EventMetadata eventMetadata) + { + eventMetadata.GetData().TryGetValue("SdkInternalEvent", out var sdkInternalEvent); + + ValidSdkEvent eventToNotify = GetSdkEventIfApplicable((SdkInternalEvent)sdkInternalEvent); + if (eventToNotify.valid) + { + Handle(eventToNotify.sdkEvent, eventMetadata); + } + + foreach (SdkEvent sdkEvent in CheckRequireAll()) + { + Handle(sdkEvent, eventMetadata); + } + } + + private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) + { + ValidSdkEvent finalSdkEvent; + finalSdkEvent.valid = false; + finalSdkEvent.sdkEvent = SdkEvent.SdkUpdate; + + ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); + if (requireAnySdkEvent.valid && !_eventsManager.EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) + && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) + { + finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; + } + + if (!_eventsManager.IsEventRegistered(finalSdkEvent.sdkEvent)) + { + finalSdkEvent.valid = requireAnySdkEvent.valid; + } + + finalSdkEvent.valid = !CheckPrerequisites(finalSdkEvent.sdkEvent); + + return finalSdkEvent; + } + + private List CheckRequireAll() + { + List events = new List(); + foreach (KeyValuePair> kvp in _config.RequireAny) + { + bool finalStatus = false; + foreach (var val in kvp.Value) + { + finalStatus &= _eventsManager.GetSdkInternalEventStatus(val); + } + if (finalStatus && _eventsManager.IsEventRegistered(kvp.Key) + && CheckPrerequisites(kvp.Key) + && ExecutionLimit(kvp.Key) == 1 + && !_eventsManager.EventAlreadyTriggered(kvp.Key)) + { + events.Add(kvp.Key); + } + } + + return events; + } + + private bool CheckPrerequisites(SdkEvent sdkEvent) + { + foreach (KeyValuePair> kvp in _config.Prerequisites) + { + if (kvp.Key == sdkEvent) + { + foreach (var val in kvp.Value) + { + if (!_eventsManager.GetSdkInternalEventStatus(val)) + return false; + } + return true; + } + } + + return true; + } + + private int ExecutionLimit(SdkEvent sdkEvent) + { + if (_config.ExecutionLimits.ContainsKey(sdkEvent)) + return -1; + + _config.ExecutionLimits.TryGetValue(sdkEvent, out int limit); + return limit; + } + + private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) + { + ValidSdkEvent validSdkEvent; + validSdkEvent.valid = false; + validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; + foreach (KeyValuePair> kvp in _config.RequireAny) + { + foreach (var val in kvp.Value) + { + if (val == sdkInternalEvent) + { + validSdkEvent.valid = true; + validSdkEvent.sdkEvent = kvp.Key; + return validSdkEvent; + } + } + } + + return validSdkEvent; + } + + void EventManager_RuleBasedSegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) + { + _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, true); + HandleInternalEvent(eventMetadata); + } + + void EventManager_FlagsUpdatedHandler(object sender, EventMetadata eventMetadata) + { + _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, true); + HandleInternalEvent(eventMetadata); + } + + void EventManager_FlagKilledNotificationHandler(object sender, EventMetadata eventMetadata) + { + _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, true); + HandleInternalEvent(eventMetadata); + } + + void EventManager_SegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) + { + _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, true); + HandleInternalEvent(eventMetadata); + } + + void EventManager_SdkReadyHandler(object sender, EventMetadata eventMetadata) + { + _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, true); + HandleInternalEvent(eventMetadata); + } + + void EventManager_SdkTimedOutHandler(object sender, EventMetadata eventMetadata) + { + _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, true); + HandleInternalEvent(eventMetadata); + } + } +} diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs new file mode 100644 index 00000000..471d677f --- /dev/null +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -0,0 +1,106 @@ +using Splitio.Domain; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Splitio.Services.Common +{ + public class EventsManager : IEventsManager + { + EventsManagerConfig _config; + Dictionary> _activeEvents; + string Triggered = "Triggered"; + string EventHandler = "EventHandler"; + Dictionary _internalEventsStatus; + + public EventsManager(EventsManagerConfig eventsManagerConfig) + { + _config = eventsManagerConfig; + _activeEvents = new Dictionary>(); + _internalEventsStatus = new Dictionary(); + } + + public Task NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) + { + return Task.CompletedTask; + } + + public bool EventAlreadyTriggered(SdkEvent sdkEvent) + { + _activeEvents.TryGetValue(sdkEvent, out Dictionary triggered); + triggered.TryGetValue(Triggered, out var trig); + return (bool)trig; + } + + public bool IsEventRegistered(SdkEvent sdkEvent) + { + return _activeEvents.ContainsKey(sdkEvent); + } + + public void Register(SdkEvent sdkEvent, IEventHandler eventHandler) + { + if (!_activeEvents.ContainsKey(sdkEvent)) + { + _activeEvents[sdkEvent] = new Dictionary() + { + {Triggered, false}, + {EventHandler, eventHandler} + }; + } + } + + public void Unregister(SdkEvent sdkEvent) + { + if (_activeEvents.ContainsKey(sdkEvent)) + { + _activeEvents.Remove(sdkEvent); + } + } + + public void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) + { + _internalEventsStatus[sdkInternalEvent] = status; + } + + public bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) + { + return _internalEventsStatus[sdkInternalEvent]; + } + + public void Destroy() + { + _activeEvents.Clear(); + } + + public virtual void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) + { + EventHandler handler = GetEventHandler(sdkInternalEvent); + if (handler != null) + { + handler(this, eventMetadata); + } + } + + private EventHandler GetEventHandler(SdkInternalEvent sdkInternalEvent) + { + switch (sdkInternalEvent) + { + case SdkInternalEvent.RuleBasedSegmentsUpdated: return RuleBasedSegmentsUpdatedHandler; + case SdkInternalEvent.FlagsUpdated: return FlagsUpdatedHandler; + case SdkInternalEvent.FlagKilledNotification: return FlagKilledNotificationHandler; + case SdkInternalEvent.SegmentsUpdated: return SegmentsUpdatedHandler; + case SdkInternalEvent.SdkReady: return SdkReadyHandler; + case SdkInternalEvent.SdkTimedOut: return SdkTimedOutHandler; + } + + return null; + } + + public event EventHandler RuleBasedSegmentsUpdatedHandler; + public event EventHandler FlagsUpdatedHandler; + public event EventHandler FlagKilledNotificationHandler; + public event EventHandler SegmentsUpdatedHandler; + public event EventHandler SdkReadyHandler; + public event EventHandler SdkTimedOutHandler; + } +} diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs new file mode 100644 index 00000000..c7d46587 --- /dev/null +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -0,0 +1,9 @@ +using Splitio.Domain; + +namespace Splitio.Services.Common +{ + public interface IEventDelivery + { + void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata); + } +} diff --git a/src/Splitio/Services/Common/IEventHandler.cs b/src/Splitio/Services/Common/IEventHandler.cs new file mode 100644 index 00000000..414473f0 --- /dev/null +++ b/src/Splitio/Services/Common/IEventHandler.cs @@ -0,0 +1,9 @@ +using Splitio.Domain; + +namespace Splitio.Services.Common +{ + public interface IEventHandler + { + void Handle(SdkEvent sdkEvent, EventMetadata eventMetadata); + } +} diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs new file mode 100644 index 00000000..3d7d91c6 --- /dev/null +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -0,0 +1,14 @@ +using Splitio.Domain; +using System.Threading.Tasks; + +namespace Splitio.Services.Common +{ + public interface IEventsManager + { + Task NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); + bool EventAlreadyTriggered(SdkEvent sdkEvent); + void Register(SdkEvent sdkEvent, IEventHandler eventHandler); + void Unregister(SdkEvent sdkEvent); + void Destroy(); + } +} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index 70d449ad..e65ae86b 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -14,18 +14,28 @@ public void BuildInstance() EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); //Assert + config.RequireAll.TryGetValue(SdkEvent.SdkReady, out var require1); + Assert.AreEqual(3, require1.Count); + Assert.IsTrue(require1.Contains(SdkInternalEvent.SegmentsUpdated)); + Assert.IsTrue(require1.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); + Assert.IsTrue(require1.Contains(SdkInternalEvent.FlagsUpdated)); + + config.Prerequisites.TryGetValue(SdkEvent.SdkUpdate, out var ready2); + Assert.IsTrue(ready2.Contains(SdkInternalEvent.SdkReady)); + config.ExecutionLimits.TryGetValue(SdkEvent.SdkReadyTimeout, out var timout); Assert.AreEqual(1, timout); config.ExecutionLimits.TryGetValue(SdkEvent.SdkUpdate, out var update); Assert.AreEqual(-1, update); + config.ExecutionLimits.TryGetValue(SdkEvent.SdkReady, out var ready); + Assert.AreEqual(1, ready); - config.RequireAny.TryGetValue(SdkEvent.SdkReadyTimeout, out var require1); - Assert.AreEqual(1, require1.Count); - Assert.IsTrue(require1.Contains(SdkInternalEvent.SdkTimedOut)); + config.RequireAny.TryGetValue(SdkEvent.SdkReadyTimeout, out var require3); + Assert.AreEqual(1, require3.Count); + Assert.IsTrue(require3.Contains(SdkInternalEvent.SdkTimedOut)); config.RequireAny.TryGetValue(SdkEvent.SdkUpdate, out var require2); - Assert.AreEqual(5, require2.Count); + Assert.AreEqual(4, require2.Count); Assert.IsTrue(require2.Contains(SdkInternalEvent.SegmentsUpdated)); - Assert.IsTrue(require2.Contains(SdkInternalEvent.LargeSegmentsUpdated)); Assert.IsTrue(require2.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagKilledNotification)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagsUpdated)); From 87a5284bc9a3ae337c70ba596a7c72aca93493ed Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 8 Dec 2025 18:57:10 -0800 Subject: [PATCH 07/87] added concurrent dictionary for storage --- src/Splitio/Services/Common/EventsManager.cs | 41 ++++++++++--------- src/Splitio/Services/Common/IEventsManager.cs | 1 - 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 471d677f..ba5cd279 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -1,28 +1,23 @@ using Splitio.Domain; using System; +using System.Collections.Concurrent; using System.Collections.Generic; -using System.Threading.Tasks; namespace Splitio.Services.Common { public class EventsManager : IEventsManager { EventsManagerConfig _config; - Dictionary> _activeEvents; + ConcurrentDictionary> _activeEvents; string Triggered = "Triggered"; string EventHandler = "EventHandler"; - Dictionary _internalEventsStatus; + ConcurrentDictionary _internalEventsStatus; public EventsManager(EventsManagerConfig eventsManagerConfig) { _config = eventsManagerConfig; - _activeEvents = new Dictionary>(); - _internalEventsStatus = new Dictionary(); - } - - public Task NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) - { - return Task.CompletedTask; + _activeEvents = new ConcurrentDictionary>(); + _internalEventsStatus = new ConcurrentDictionary(); } public bool EventAlreadyTriggered(SdkEvent sdkEvent) @@ -39,32 +34,40 @@ public bool IsEventRegistered(SdkEvent sdkEvent) public void Register(SdkEvent sdkEvent, IEventHandler eventHandler) { - if (!_activeEvents.ContainsKey(sdkEvent)) + if (_activeEvents.TryGetValue(sdkEvent, out var dict)) { - _activeEvents[sdkEvent] = new Dictionary() + if (dict.Count == 0) { - {Triggered, false}, - {EventHandler, eventHandler} - }; + _activeEvents.TryAdd(sdkEvent, new Dictionary() + { + {Triggered, false}, + {EventHandler, eventHandler} + }); + } } } public void Unregister(SdkEvent sdkEvent) { - if (_activeEvents.ContainsKey(sdkEvent)) + if (_activeEvents.TryGetValue(sdkEvent, out var dict)) { - _activeEvents.Remove(sdkEvent); + if (dict.Count < 1) + { + _activeEvents.TryRemove(sdkEvent, out _); + } } } public void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) { - _internalEventsStatus[sdkInternalEvent] = status; + _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, + (_, oldValue) => status); } public bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) { - return _internalEventsStatus[sdkInternalEvent]; + _internalEventsStatus.TryGetValue(sdkInternalEvent, out var status); + return status; } public void Destroy() diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index 3d7d91c6..b5f91181 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -5,7 +5,6 @@ namespace Splitio.Services.Common { public interface IEventsManager { - Task NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); bool EventAlreadyTriggered(SdkEvent sdkEvent); void Register(SdkEvent sdkEvent, IEventHandler eventHandler); void Unregister(SdkEvent sdkEvent); From c60d8443c13ddde0acadce65324c827b97012b80 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 9 Dec 2025 15:29:47 -0800 Subject: [PATCH 08/87] Added event delivery queue and tests --- src/Splitio/Domain/EventsManagerConfig.cs | 3 +- src/Splitio/Services/Common/EventDelivery.cs | 60 +++++- src/Splitio/Services/Common/EventHandler.cs | 53 +++-- src/Splitio/Services/Common/EventsManager.cs | 106 +++++++--- src/Splitio/Services/Common/IEventsManager.cs | 4 +- .../Services/Common/QueuedSdkEventDto.cs | 11 + .../Integration Tests/SdkEventsTest.cs | 79 +++++++ .../Unit Tests/Common/EventsManagerTests.cs | 198 ++++++++++++++++++ 8 files changed, 464 insertions(+), 50 deletions(-) create mode 100644 src/Splitio/Services/Common/QueuedSdkEventDto.cs create mode 100644 tests/Splitio-tests/Integration Tests/SdkEventsTest.cs create mode 100644 tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index c260f113..44583f8d 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -33,7 +33,8 @@ public static EventsManagerConfig BuildEventsManagerConfig() { SdkInternalEvent.RuleBasedSegmentsUpdated, SdkInternalEvent.FlagsUpdated, - SdkInternalEvent.SegmentsUpdated + SdkInternalEvent.SegmentsUpdated, + SdkInternalEvent.SdkReady } } }; diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index ce1f2a06..95f8567a 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,16 +1,70 @@ using Splitio.Domain; +using Splitio.Services.EventSource.Workers; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; using System; +using System.Threading.Tasks; namespace Splitio.Services.Common { - public class EventDelivery : IEventDelivery + public class EventDelivery : BaseWorker, IEventDelivery, IQueueObserver { - EventsManagerConfig _config; EventsManager _eventsManager; + private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); + private readonly SplitQueue _queue; + public EventDelivery(EventsManager eventsManager) : base("EventDelivery", WrapperAdapter.Instance().GetLogger(typeof(EventDelivery))) + { + _eventsManager = eventsManager; + _queue = new SplitQueue(); + _queue.AddObserver(this); + } public void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata) - { } + { + Task.Run(() => AddToQueue(sdkEvent, eventMetadata)); + } + public async Task AddToQueue(SdkEvent sdkEvent, EventMetadata eventMetadata) + { + try + { + if (!_running) + { + _logger.Error("EventDelivery Worker not running."); + return; + } + + _logger.Debug($"EventDelivery: Add to queue: {sdkEvent}"); + await _queue.EnqueueAsync(new QueuedSdkEventDto { SdkEvent = sdkEvent, EventMetadata = eventMetadata }); + } + catch (Exception ex) + { + _logger.Error($"EventDelivery error AddToQueue: {ex.Message}"); + } + } + + public async Task Notify() + { + try + { + if (!_queue.TryDequeue(out QueuedSdkEventDto sdkEventDto)) return; + + _logger.Debug($"EventDelivery: SdkEvent dequeue: {sdkEventDto.SdkEvent}"); + Action callbackAction = _eventsManager.GetCallbackAction(sdkEventDto.SdkEvent); + if (callbackAction != null) + { + _eventsManager.SetSdkEventTriggered(sdkEventDto.SdkEvent); + _logger.Debug($"EventDelivery: executing callback notification for Event {sdkEventDto.SdkEvent}"); + callbackAction(sdkEventDto.EventMetadata); + } + } + catch (Exception ex) + { + if (ex is OperationCanceledException) return; + + _logger.Debug($"EventDelivery worker Execute exception", ex); + } + } } } diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index 4661f045..feed743d 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -1,10 +1,13 @@ using Splitio.Domain; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; using System.Collections.Generic; namespace Splitio.Services.Common { public class EventHandler : IEventHandler { + private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventHandler"); EventsManagerConfig _config; EventsManager _eventsManager; EventDelivery _eventDelivery; @@ -14,6 +17,7 @@ struct ValidSdkEvent public bool valid; } + #region Public Methods public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager, EventDelivery eventDelivery) { _config = eventsManagerConfig; @@ -30,14 +34,16 @@ public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager event public void Handle(SdkEvent sdkEvent, EventMetadata eventMetadata) { + _logger.Debug($"EventHandler: Delivering notification for Event {sdkEvent}"); _eventDelivery.Deliver(sdkEvent, eventMetadata); } + #endregion - void HandleInternalEvent(EventMetadata eventMetadata) + #region Private Methods + private void HandleInternalEvent(EventMetadata eventMetadata, SdkInternalEvent sdkInternalEvent) { - eventMetadata.GetData().TryGetValue("SdkInternalEvent", out var sdkInternalEvent); - - ValidSdkEvent eventToNotify = GetSdkEventIfApplicable((SdkInternalEvent)sdkInternalEvent); + _logger.Debug($"EventHandler: Handling internal event {sdkInternalEvent}"); + ValidSdkEvent eventToNotify = GetSdkEventIfApplicable(sdkInternalEvent); if (eventToNotify.valid) { Handle(eventToNotify.sdkEvent, eventMetadata); @@ -56,9 +62,16 @@ private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) finalSdkEvent.sdkEvent = SdkEvent.SdkUpdate; ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); + if (!requireAnySdkEvent.valid) + { + _logger.Debug($"EventHandler: No Event available for internal event {sdkInternalEvent}"); + return requireAnySdkEvent; + } + if (requireAnySdkEvent.valid && !_eventsManager.EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) { + _logger.Debug($"EventHandler: Detected Event {requireAnySdkEvent.sdkEvent} is available for internal event {sdkInternalEvent}"); finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; } @@ -67,26 +80,31 @@ private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) finalSdkEvent.valid = requireAnySdkEvent.valid; } - finalSdkEvent.valid = !CheckPrerequisites(finalSdkEvent.sdkEvent); - + finalSdkEvent.valid = CheckPrerequisites(finalSdkEvent.sdkEvent); + if (finalSdkEvent.valid) + { + _logger.Debug($"EventHandler: Event {requireAnySdkEvent.sdkEvent} is eligable for notification."); + } return finalSdkEvent; } private List CheckRequireAll() { List events = new List(); - foreach (KeyValuePair> kvp in _config.RequireAny) + foreach (KeyValuePair> kvp in _config.RequireAll) { - bool finalStatus = false; + bool finalStatus = true; foreach (var val in kvp.Value) { finalStatus &= _eventsManager.GetSdkInternalEventStatus(val); } if (finalStatus && _eventsManager.IsEventRegistered(kvp.Key) && CheckPrerequisites(kvp.Key) - && ExecutionLimit(kvp.Key) == 1 - && !_eventsManager.EventAlreadyTriggered(kvp.Key)) + && ((ExecutionLimit(kvp.Key) == 1 && !_eventsManager.EventAlreadyTriggered(kvp.Key)) + || (ExecutionLimit(kvp.Key) == -1)) + && kvp.Value.Count > 0) { + _logger.Debug($"EventHandler: Event {kvp.Key} is eligable as require all for notification."); events.Add(kvp.Key); } } @@ -114,7 +132,7 @@ private bool CheckPrerequisites(SdkEvent sdkEvent) private int ExecutionLimit(SdkEvent sdkEvent) { - if (_config.ExecutionLimits.ContainsKey(sdkEvent)) + if (!_config.ExecutionLimits.ContainsKey(sdkEvent)) return -1; _config.ExecutionLimits.TryGetValue(sdkEvent, out int limit); @@ -145,37 +163,38 @@ private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) void EventManager_RuleBasedSegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) { _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, true); - HandleInternalEvent(eventMetadata); + HandleInternalEvent(eventMetadata, SdkInternalEvent.RuleBasedSegmentsUpdated); } void EventManager_FlagsUpdatedHandler(object sender, EventMetadata eventMetadata) { _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, true); - HandleInternalEvent(eventMetadata); + HandleInternalEvent(eventMetadata, SdkInternalEvent.FlagsUpdated); } void EventManager_FlagKilledNotificationHandler(object sender, EventMetadata eventMetadata) { _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, true); - HandleInternalEvent(eventMetadata); + HandleInternalEvent(eventMetadata, SdkInternalEvent.FlagKilledNotification); } void EventManager_SegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) { _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, true); - HandleInternalEvent(eventMetadata); + HandleInternalEvent(eventMetadata, SdkInternalEvent.SegmentsUpdated); } void EventManager_SdkReadyHandler(object sender, EventMetadata eventMetadata) { _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, true); - HandleInternalEvent(eventMetadata); + HandleInternalEvent(eventMetadata, SdkInternalEvent.SdkReady); } void EventManager_SdkTimedOutHandler(object sender, EventMetadata eventMetadata) { _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, true); - HandleInternalEvent(eventMetadata); + HandleInternalEvent(eventMetadata, SdkInternalEvent.SdkTimedOut); } + #endregion } } diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index ba5cd279..cb77a3fd 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -1,4 +1,6 @@ using Splitio.Domain; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -7,24 +9,35 @@ namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - EventsManagerConfig _config; ConcurrentDictionary> _activeEvents; - string Triggered = "Triggered"; - string EventHandler = "EventHandler"; + readonly string Triggered = "Triggered"; + readonly string EventHandler = "EventHandler"; ConcurrentDictionary _internalEventsStatus; + private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - public EventsManager(EventsManagerConfig eventsManagerConfig) + public event EventHandler RuleBasedSegmentsUpdatedHandler; + public event EventHandler FlagsUpdatedHandler; + public event EventHandler FlagKilledNotificationHandler; + public event EventHandler SegmentsUpdatedHandler; + public event EventHandler SdkReadyHandler; + public event EventHandler SdkTimedOutHandler; + + #region Public Methods + public EventsManager() { - _config = eventsManagerConfig; _activeEvents = new ConcurrentDictionary>(); - _internalEventsStatus = new ConcurrentDictionary(); + _internalEventsStatus = BuildInternalSdkEventStatus(); } public bool EventAlreadyTriggered(SdkEvent sdkEvent) { - _activeEvents.TryGetValue(sdkEvent, out Dictionary triggered); - triggered.TryGetValue(Triggered, out var trig); - return (bool)trig; + if (_activeEvents.TryGetValue(sdkEvent, out Dictionary triggered)) + { + triggered.TryGetValue(Triggered, out var trig); + return (bool)trig; + } + + return false; } public bool IsEventRegistered(SdkEvent sdkEvent) @@ -32,36 +45,65 @@ public bool IsEventRegistered(SdkEvent sdkEvent) return _activeEvents.ContainsKey(sdkEvent); } - public void Register(SdkEvent sdkEvent, IEventHandler eventHandler) + public Action GetCallbackAction(SdkEvent sdkEvent) { if (_activeEvents.TryGetValue(sdkEvent, out var dict)) { - if (dict.Count == 0) - { - _activeEvents.TryAdd(sdkEvent, new Dictionary() - { - {Triggered, false}, - {EventHandler, eventHandler} - }); - } + dict.TryGetValue(EventHandler, out var callbackAction); + return (Action)callbackAction; } + + return null; } + public void Register(SdkEvent sdkEvent, Action callbackAction) + { + _activeEvents.TryGetValue(sdkEvent, out var dict); + if (dict == null) + { + _activeEvents.TryAdd(sdkEvent, new Dictionary() + { + {Triggered, false}, + {EventHandler, callbackAction} + }); + _logger.Debug($"EventManager: Event {sdkEvent} is registered"); + } + } + public void Unregister(SdkEvent sdkEvent) { if (_activeEvents.TryGetValue(sdkEvent, out var dict)) { - if (dict.Count < 1) + if (dict.Count > 0) { _activeEvents.TryRemove(sdkEvent, out _); + _logger.Debug($"EventManager: Event {sdkEvent} is unregistered"); } } } + public void SetSdkEventTriggered(SdkEvent sdkEvent) + { + if (!_activeEvents.TryGetValue(sdkEvent, out var dict)) + { + return; + } + + if ((bool)dict[Triggered]) + { + return; + } + + Dictionary dict2 = new Dictionary(dict); + dict2[Triggered] = true; + _activeEvents.TryUpdate(sdkEvent, dict2, dict); + } + public void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) { _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, (_, oldValue) => status); + _logger.Debug($"EventManager: Internal Event {sdkInternalEvent} status is updated to {status}"); } public bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) @@ -72,7 +114,9 @@ public bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) public void Destroy() { - _activeEvents.Clear(); + _activeEvents.Clear(); + _internalEventsStatus.Clear(); + _logger.Debug("EventManager is destroyed."); } public virtual void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) @@ -80,10 +124,24 @@ public virtual void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventM EventHandler handler = GetEventHandler(sdkInternalEvent); if (handler != null) { + _logger.Debug($"EventManager: Triggering handle for Internal Event {sdkInternalEvent}"); handler(this, eventMetadata); } } + #endregion + #region Private Methods + private ConcurrentDictionary BuildInternalSdkEventStatus() + { + ConcurrentDictionary statuses = new ConcurrentDictionary(); + statuses.TryAdd(SdkInternalEvent.SdkReady, false); + statuses.TryAdd(SdkInternalEvent.RuleBasedSegmentsUpdated, false); + statuses.TryAdd(SdkInternalEvent.SdkTimedOut, false); + statuses.TryAdd(SdkInternalEvent.SegmentsUpdated, false); + statuses.TryAdd(SdkInternalEvent.FlagKilledNotification, false); + statuses.TryAdd(SdkInternalEvent.FlagsUpdated, false); + return statuses; + } private EventHandler GetEventHandler(SdkInternalEvent sdkInternalEvent) { switch (sdkInternalEvent) @@ -98,12 +156,6 @@ private EventHandler GetEventHandler(SdkInternalEvent sdkInternal return null; } - - public event EventHandler RuleBasedSegmentsUpdatedHandler; - public event EventHandler FlagsUpdatedHandler; - public event EventHandler FlagKilledNotificationHandler; - public event EventHandler SegmentsUpdatedHandler; - public event EventHandler SdkReadyHandler; - public event EventHandler SdkTimedOutHandler; + #endregion } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index b5f91181..086cb9f1 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,12 +1,12 @@ using Splitio.Domain; -using System.Threading.Tasks; +using System; namespace Splitio.Services.Common { public interface IEventsManager { bool EventAlreadyTriggered(SdkEvent sdkEvent); - void Register(SdkEvent sdkEvent, IEventHandler eventHandler); + void Register(SdkEvent sdkEvent, Action callbackAction); void Unregister(SdkEvent sdkEvent); void Destroy(); } diff --git a/src/Splitio/Services/Common/QueuedSdkEventDto.cs b/src/Splitio/Services/Common/QueuedSdkEventDto.cs new file mode 100644 index 00000000..b189a359 --- /dev/null +++ b/src/Splitio/Services/Common/QueuedSdkEventDto.cs @@ -0,0 +1,11 @@ +using Splitio.Domain; +using System; + +namespace Splitio.Services.EventSource.Workers +{ + public class QueuedSdkEventDto + { + public SdkEvent SdkEvent { get; set; } + public EventMetadata EventMetadata { get; set; } + } +} diff --git a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs new file mode 100644 index 00000000..fbc5f21b --- /dev/null +++ b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs @@ -0,0 +1,79 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Splitio.Domain; +using Splitio.Services.Common; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using EventHandler = Splitio.Services.Common.EventHandler; + +namespace Splitio_Tests.Integration_Tests +{ + [TestClass] + public class SdkEventsTest + { + private bool _sdkUpdate = false; + private bool _sdkReady = false; + private EventMetadata _eventMetadata; + + [TestMethod] + public void TriggerAndCatchEventsTest() + { + //Arrange + EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + EventsManager eventsManager = new EventsManager(); + EventDelivery eventDelivery = new EventDelivery(eventsManager); + eventDelivery.Start(); + EventHandler eventHandler = new EventHandler(config, eventsManager, eventDelivery); + eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + + Dictionary metaData = new Dictionary + { + { "flags", new List {{ "flag1" }} } + }; + Dictionary metaData2 = new Dictionary(); + + eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData2)); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData2)); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + Assert.IsFalse(_sdkUpdate); + Assert.IsFalse(_sdkReady); + + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData2)); + Thread.Sleep(2000); + Assert.IsTrue(_sdkReady); + Assert.IsFalse(_sdkUpdate); + + _sdkReady = false; + _sdkUpdate = false; + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + Thread.Sleep(2000); + Assert.IsTrue(_sdkUpdate); + Assert.IsFalse(_sdkReady); + + _sdkUpdate = false; + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + Thread.Sleep(2000); + Assert.IsTrue(_sdkUpdate); + Assert.IsFalse(_sdkReady); + + eventDelivery.Stop(); + eventsManager.Destroy(); + } + + private void sdkUpdate_callback(EventMetadata metadata) + { + _sdkUpdate = true; + _eventMetadata = metadata; + } + + private void sdkReady_callback(EventMetadata metadata) + { + _sdkReady = true; + _eventMetadata = metadata; + } + } +} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs new file mode 100644 index 00000000..97e4a945 --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -0,0 +1,198 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Splitio.Domain; +using Splitio.Services.Common; +using System.Collections.Generic; +using System.Threading; + +namespace Splitio_Tests.Unit_Tests.Common +{ + [TestClass] + public class EventsManagerTests + { + private bool RuleBasedSegmentsUpdated = false; + private bool FlagsUpdated = false; + private bool FlagKilledNotification = false; + private bool SegmentsUpdated = false; + private bool SdkReady = false; + private bool SdkTimedOut = false; + private EventMetadata eMetadata = null; + + [TestMethod] + public void TestFiringInternalEvents() + { + //Act + EventsManager eventsManager = new EventsManager(); + eventsManager.RuleBasedSegmentsUpdatedHandler += EventManager_RuleBasedSegmentsUpdatedHandler; + eventsManager.FlagKilledNotificationHandler += EventManager_FlagKilledNotificationHandler; + eventsManager.FlagsUpdatedHandler += EventManager_FlagsUpdatedHandler; + eventsManager.SegmentsUpdatedHandler += EventManager_SegmentsUpdatedHandler; + eventsManager.SdkReadyHandler += EventManager_SdkReadyHandler; + eventsManager.SdkTimedOutHandler += EventManager_SdkTimedOutHandler; + + Dictionary metaData = new Dictionary + { + { "flags", new List {{ "flag1" }} } + }; + + eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(RuleBasedSegmentsUpdated); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(FlagKilledNotification); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(SdkReady); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(SdkTimedOut); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(FlagsUpdated); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(SegmentsUpdated); + VerifyMetadata(eMetadata); + } + + [TestMethod] + public void TestRegisterEvents() + { + EventsManager eventsManager = new EventsManager(); + eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + + Assert.IsFalse(eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)); + Assert.IsFalse(eventsManager.EventAlreadyTriggered(SdkEvent.SdkUpdate)); + Assert.IsTrue(eventsManager.IsEventRegistered(SdkEvent.SdkUpdate)); + Assert.IsTrue(eventsManager.IsEventRegistered(SdkEvent.SdkReady)); + Assert.IsFalse(eventsManager.IsEventRegistered(SdkEvent.SdkReadyTimeout)); + Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkUpdate) == sdkUpdate_callback); + Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkReady) == sdkReady_callback); + Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkReadyTimeout) == null); + + eventsManager.SetSdkEventTriggered(SdkEvent.SdkReady); + Assert.IsTrue(eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)); + Assert.IsFalse(eventsManager.EventAlreadyTriggered(SdkEvent.SdkUpdate)); + + eventsManager.Unregister(SdkEvent.SdkUpdate); + Assert.IsFalse(eventsManager.IsEventRegistered(SdkEvent.SdkUpdate)); + Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkUpdate) == null); + + eventsManager.Destroy(); + Assert.IsFalse(eventsManager.IsEventRegistered(SdkEvent.SdkReady)); + } + + [TestMethod] + public void TestEventsStatus() + { + EventsManager eventsManager = new EventsManager(); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification)); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated)); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated)); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut)); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, true); + Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, true); + Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, true); + Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, true); + Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, true); + Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, true); + Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut)); + + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, false); + Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); + } + + void ResetAllVariables() + { + RuleBasedSegmentsUpdated = false; + FlagsUpdated = false; + FlagKilledNotification = false; + SegmentsUpdated = false; + SdkReady = false; + SdkTimedOut = false; + eMetadata = null; + } + void VerifyMetadata(EventMetadata eMetdata) + { + Assert.IsTrue(eMetadata.ContainKey("flags")); + List flags = (List)eMetadata.GetData()["flags"]; + Assert.IsTrue(flags.Count == 1); + Assert.IsTrue(flags.Contains("flag1")); + } + + void EventManager_RuleBasedSegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) + { + RuleBasedSegmentsUpdated = true; + eMetadata = eventMetadata; + } + + void EventManager_FlagsUpdatedHandler(object sender, EventMetadata eventMetadata) + { + FlagsUpdated = true; + eMetadata = eventMetadata; + } + + void EventManager_FlagKilledNotificationHandler(object sender, EventMetadata eventMetadata) + { + FlagKilledNotification = true; + eMetadata = eventMetadata; + } + + void EventManager_SegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) + { + SegmentsUpdated = true; + eMetadata = eventMetadata; + } + + void EventManager_SdkReadyHandler(object sender, EventMetadata eventMetadata) + { + SdkReady = true; + eMetadata = eventMetadata; + } + + void EventManager_SdkTimedOutHandler(object sender, EventMetadata eventMetadata) + { + SdkTimedOut = true; + eMetadata = eventMetadata; + } + + private void sdkUpdate_callback(EventMetadata metadata) + { + SdkReady = true; + } + + private void sdkReady_callback(EventMetadata metadata) + { + SdkReady = true; + } + } +} From 80d8fc6a0c58a4176d4f3679ffc7c175af696488 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 9 Dec 2025 21:43:15 -0800 Subject: [PATCH 09/87] added event handler and event delivery classes --- src/Splitio/Services/Common/EventHandler.cs | 4 +- .../Unit Tests/Common/EventHandlerTest.cs | 61 +++++++++++++++++++ .../Common/EventsManagerConfigTests.cs | 2 +- 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index feed743d..c3ddfb6a 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -10,7 +10,7 @@ public class EventHandler : IEventHandler private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventHandler"); EventsManagerConfig _config; EventsManager _eventsManager; - EventDelivery _eventDelivery; + IEventDelivery _eventDelivery; struct ValidSdkEvent { public SdkEvent sdkEvent; @@ -18,7 +18,7 @@ struct ValidSdkEvent } #region Public Methods - public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager, EventDelivery eventDelivery) + public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager, IEventDelivery eventDelivery) { _config = eventsManagerConfig; _eventsManager = eventsManager; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs new file mode 100644 index 00000000..2c743ba0 --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs @@ -0,0 +1,61 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Splitio.Domain; +using Splitio.Services.Common; +using System.Collections.Generic; +using EventHandler = Splitio.Services.Common.EventHandler; + +namespace Splitio_Tests.Unit_Tests.Common +{ + [TestClass] + public class EventHandlerTest + { + + [TestMethod] + public void TriggerAndCatchEventsTest() + { + //Arrange + EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + EventsManager eventsManager = new EventsManager(); + Mock eventDelivery = new Mock(); + EventHandler eventHandler = new EventHandler(config, eventsManager, eventDelivery.Object); + eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + + Dictionary metaData = new Dictionary + { + { "flags", new List {{ "flag1" }} } + }; + EventMetadata eventMetadata = new EventMetadata(metaData); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, eventMetadata); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, eventMetadata); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, eventMetadata); + + eventDelivery.Verify(mock => mock.Deliver(It.IsAny (), It.IsAny()), Times.Never); + + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); + eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkReady, It.IsAny()), Times.Once); + eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkUpdate, It.IsAny()), Times.Never); + eventsManager.SetSdkEventTriggered(SdkEvent.SdkReady); + + eventDelivery.Reset(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkUpdate, It.IsAny()), Times.Once); + eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkReady, It.IsAny()), Times.Never); + eventsManager.SetSdkEventTriggered(SdkEvent.SdkUpdate); + + eventDelivery.Reset(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkUpdate, It.IsAny()), Times.Once); + eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkReady, It.IsAny()), Times.Never); + } + + private void sdkUpdate_callback(EventMetadata metadata) + { + } + + private void sdkReady_callback(EventMetadata metadata) + { + } + } +} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index e65ae86b..5738adeb 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -15,7 +15,7 @@ public void BuildInstance() //Assert config.RequireAll.TryGetValue(SdkEvent.SdkReady, out var require1); - Assert.AreEqual(3, require1.Count); + Assert.AreEqual(4, require1.Count); Assert.IsTrue(require1.Contains(SdkInternalEvent.SegmentsUpdated)); Assert.IsTrue(require1.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); Assert.IsTrue(require1.Contains(SdkInternalEvent.FlagsUpdated)); From 376e73918e554a3db0bacc9dbf90b3ca84b745f3 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 13:25:17 -0800 Subject: [PATCH 10/87] added event manager and handler --- src/Splitio/Services/Common/EventDelivery.cs | 70 --------- src/Splitio/Services/Common/EventHandler.cs | 39 +++-- src/Splitio/Services/Common/EventsManager.cs | 139 ++++++++---------- src/Splitio/Services/Common/IEventDelivery.cs | 9 -- src/Splitio/Services/Common/IEventHandler.cs | 6 +- .../Services/Common/QueuedSdkEventDto.cs | 11 -- .../Integration Tests/SdkEventsTest.cs | 17 +-- .../Unit Tests/Common/EventHandlerTest.cs | 129 +++++++++++++--- .../Unit Tests/Common/EventsManagerTests.cs | 78 ++++++---- 9 files changed, 252 insertions(+), 246 deletions(-) delete mode 100644 src/Splitio/Services/Common/EventDelivery.cs delete mode 100644 src/Splitio/Services/Common/IEventDelivery.cs delete mode 100644 src/Splitio/Services/Common/QueuedSdkEventDto.cs diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs deleted file mode 100644 index 95f8567a..00000000 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Splitio.Domain; -using Splitio.Services.EventSource.Workers; -using Splitio.Services.Logger; -using Splitio.Services.Shared.Classes; -using System; -using System.Threading.Tasks; - -namespace Splitio.Services.Common -{ - public class EventDelivery : BaseWorker, IEventDelivery, IQueueObserver - { - EventsManager _eventsManager; - private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); - private readonly SplitQueue _queue; - - public EventDelivery(EventsManager eventsManager) : base("EventDelivery", WrapperAdapter.Instance().GetLogger(typeof(EventDelivery))) - { - _eventsManager = eventsManager; - _queue = new SplitQueue(); - _queue.AddObserver(this); - } - - public void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata) - { - Task.Run(() => AddToQueue(sdkEvent, eventMetadata)); - } - - public async Task AddToQueue(SdkEvent sdkEvent, EventMetadata eventMetadata) - { - try - { - if (!_running) - { - _logger.Error("EventDelivery Worker not running."); - return; - } - - _logger.Debug($"EventDelivery: Add to queue: {sdkEvent}"); - await _queue.EnqueueAsync(new QueuedSdkEventDto { SdkEvent = sdkEvent, EventMetadata = eventMetadata }); - } - catch (Exception ex) - { - _logger.Error($"EventDelivery error AddToQueue: {ex.Message}"); - } - } - - public async Task Notify() - { - try - { - if (!_queue.TryDequeue(out QueuedSdkEventDto sdkEventDto)) return; - - _logger.Debug($"EventDelivery: SdkEvent dequeue: {sdkEventDto.SdkEvent}"); - Action callbackAction = _eventsManager.GetCallbackAction(sdkEventDto.SdkEvent); - if (callbackAction != null) - { - _eventsManager.SetSdkEventTriggered(sdkEventDto.SdkEvent); - _logger.Debug($"EventDelivery: executing callback notification for Event {sdkEventDto.SdkEvent}"); - callbackAction(sdkEventDto.EventMetadata); - } - } - catch (Exception ex) - { - if (ex is OperationCanceledException) return; - - _logger.Debug($"EventDelivery worker Execute exception", ex); - } - } - } -} diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index c3ddfb6a..48b0926b 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -5,12 +5,12 @@ namespace Splitio.Services.Common { + public class EventHandler : IEventHandler { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventHandler"); EventsManagerConfig _config; EventsManager _eventsManager; - IEventDelivery _eventDelivery; struct ValidSdkEvent { public SdkEvent sdkEvent; @@ -18,24 +18,32 @@ struct ValidSdkEvent } #region Public Methods - public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager, IEventDelivery eventDelivery) + public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager) { _config = eventsManagerConfig; _eventsManager = eventsManager; - _eventDelivery = eventDelivery; + } + public void SubscribeInternalEvents() + { _eventsManager.RuleBasedSegmentsUpdatedHandler += EventManager_RuleBasedSegmentsUpdatedHandler; _eventsManager.FlagKilledNotificationHandler += EventManager_FlagKilledNotificationHandler; _eventsManager.FlagsUpdatedHandler += EventManager_FlagsUpdatedHandler; _eventsManager.SegmentsUpdatedHandler += EventManager_SegmentsUpdatedHandler; _eventsManager.SdkReadyHandler += EventManager_SdkReadyHandler; _eventsManager.SdkTimedOutHandler += EventManager_SdkTimedOutHandler; + _logger.Debug("EventHandler: Subscription to internal events are added."); } - public void Handle(SdkEvent sdkEvent, EventMetadata eventMetadata) + public void ClearInternalEventsSubscription() { - _logger.Debug($"EventHandler: Delivering notification for Event {sdkEvent}"); - _eventDelivery.Deliver(sdkEvent, eventMetadata); + _eventsManager.RuleBasedSegmentsUpdatedHandler -= EventManager_RuleBasedSegmentsUpdatedHandler; + _eventsManager.FlagKilledNotificationHandler -= EventManager_FlagKilledNotificationHandler; + _eventsManager.FlagsUpdatedHandler -= EventManager_FlagsUpdatedHandler; + _eventsManager.SegmentsUpdatedHandler -= EventManager_SegmentsUpdatedHandler; + _eventsManager.SdkReadyHandler -= EventManager_SdkReadyHandler; + _eventsManager.SdkTimedOutHandler -= EventManager_SdkTimedOutHandler; + _logger.Debug("EventHandler: Subscription to internal events are removed."); } #endregion @@ -46,12 +54,16 @@ private void HandleInternalEvent(EventMetadata eventMetadata, SdkInternalEvent s ValidSdkEvent eventToNotify = GetSdkEventIfApplicable(sdkInternalEvent); if (eventToNotify.valid) { - Handle(eventToNotify.sdkEvent, eventMetadata); + _logger.Debug($"EventHandler: Firing Sdk event {eventToNotify.sdkEvent}"); + _eventsManager.OnSdkEvent(eventToNotify.sdkEvent, eventMetadata); + _eventsManager.UpdateSdkEventStatus(eventToNotify.sdkEvent, true); } foreach (SdkEvent sdkEvent in CheckRequireAll()) { - Handle(sdkEvent, eventMetadata); + _logger.Debug($"EventHandler: Firing Sdk event {sdkEvent}"); + _eventsManager.OnSdkEvent(sdkEvent, eventMetadata); + _eventsManager.UpdateSdkEventStatus(sdkEvent, true); } } @@ -68,18 +80,13 @@ private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) return requireAnySdkEvent; } - if (requireAnySdkEvent.valid && !_eventsManager.EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) + if (requireAnySdkEvent.valid && !_eventsManager.GetSdkEventStatus(requireAnySdkEvent.sdkEvent) && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) { _logger.Debug($"EventHandler: Detected Event {requireAnySdkEvent.sdkEvent} is available for internal event {sdkInternalEvent}"); finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; } - if (!_eventsManager.IsEventRegistered(finalSdkEvent.sdkEvent)) - { - finalSdkEvent.valid = requireAnySdkEvent.valid; - } - finalSdkEvent.valid = CheckPrerequisites(finalSdkEvent.sdkEvent); if (finalSdkEvent.valid) { @@ -98,9 +105,9 @@ private List CheckRequireAll() { finalStatus &= _eventsManager.GetSdkInternalEventStatus(val); } - if (finalStatus && _eventsManager.IsEventRegistered(kvp.Key) + if (finalStatus && CheckPrerequisites(kvp.Key) - && ((ExecutionLimit(kvp.Key) == 1 && !_eventsManager.EventAlreadyTriggered(kvp.Key)) + && ((ExecutionLimit(kvp.Key) == 1 && !_eventsManager.GetSdkEventStatus(kvp.Key)) || (ExecutionLimit(kvp.Key) == -1)) && kvp.Value.Count > 0) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index cb77a3fd..d00280ef 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -3,15 +3,12 @@ using Splitio.Services.Shared.Classes; using System; using System.Collections.Concurrent; -using System.Collections.Generic; namespace Splitio.Services.Common { - public class EventsManager : IEventsManager + public class EventsManager { - ConcurrentDictionary> _activeEvents; - readonly string Triggered = "Triggered"; - readonly string EventHandler = "EventHandler"; + ConcurrentDictionary _eventsStatus; ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); @@ -22,81 +19,28 @@ public class EventsManager : IEventsManager public event EventHandler SdkReadyHandler; public event EventHandler SdkTimedOutHandler; + public event EventHandler PublicSdkReadyHandler; + public event EventHandler PublicSdkUpdateHandler; + public event EventHandler PublicSdkTimedOutHandler; + #region Public Methods public EventsManager() { - _activeEvents = new ConcurrentDictionary>(); + _eventsStatus = BuildSdkEventStatus(); _internalEventsStatus = BuildInternalSdkEventStatus(); } - public bool EventAlreadyTriggered(SdkEvent sdkEvent) - { - if (_activeEvents.TryGetValue(sdkEvent, out Dictionary triggered)) - { - triggered.TryGetValue(Triggered, out var trig); - return (bool)trig; - } - - return false; - } - - public bool IsEventRegistered(SdkEvent sdkEvent) - { - return _activeEvents.ContainsKey(sdkEvent); - } - - public Action GetCallbackAction(SdkEvent sdkEvent) - { - if (_activeEvents.TryGetValue(sdkEvent, out var dict)) - { - dict.TryGetValue(EventHandler, out var callbackAction); - return (Action)callbackAction; - } - - return null; - } - - public void Register(SdkEvent sdkEvent, Action callbackAction) + public void UpdateSdkEventStatus(SdkEvent sdkEvent, bool status) { - _activeEvents.TryGetValue(sdkEvent, out var dict); - if (dict == null) - { - _activeEvents.TryAdd(sdkEvent, new Dictionary() - { - {Triggered, false}, - {EventHandler, callbackAction} - }); - _logger.Debug($"EventManager: Event {sdkEvent} is registered"); - } - } - - public void Unregister(SdkEvent sdkEvent) - { - if (_activeEvents.TryGetValue(sdkEvent, out var dict)) - { - if (dict.Count > 0) - { - _activeEvents.TryRemove(sdkEvent, out _); - _logger.Debug($"EventManager: Event {sdkEvent} is unregistered"); - } - } + _eventsStatus.AddOrUpdate(sdkEvent, status, + (_, oldValue) => status); + _logger.Debug($"EventManager: Sdk Event {sdkEvent} status is updated to {status}"); } - public void SetSdkEventTriggered(SdkEvent sdkEvent) + public bool GetSdkEventStatus(SdkEvent sdkEvent) { - if (!_activeEvents.TryGetValue(sdkEvent, out var dict)) - { - return; - } - - if ((bool)dict[Triggered]) - { - return; - } - - Dictionary dict2 = new Dictionary(dict); - dict2[Triggered] = true; - _activeEvents.TryUpdate(sdkEvent, dict2, dict); + _eventsStatus.TryGetValue(sdkEvent, out var status); + return status; } public void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) @@ -112,20 +56,37 @@ public bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) return status; } - public void Destroy() - { - _activeEvents.Clear(); - _internalEventsStatus.Clear(); - _logger.Debug("EventManager is destroyed."); - } - public virtual void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) { EventHandler handler = GetEventHandler(sdkInternalEvent); if (handler != null) { _logger.Debug($"EventManager: Triggering handle for Internal Event {sdkInternalEvent}"); - handler(this, eventMetadata); + try + { + handler(this, eventMetadata); + } + catch (Exception e) + { + _logger.Error($"EventManager: Failed to run internal event {sdkInternalEvent} handler {e.Message}", e); + } + } + } + + public virtual void OnSdkEvent(SdkEvent sdkEvent, EventMetadata eventMetadata) + { + EventHandler handler = GetPublicEventHandler(sdkEvent); + if (handler != null) + { + _logger.Debug($"EventManager: Triggering handle for Sdk Event {sdkEvent}"); + try + { + handler(this, eventMetadata); + } + catch (Exception e) + { + _logger.Error($"EventManager: Failed to run event {sdkEvent} handler {e.Message}", e); + } } } #endregion @@ -142,6 +103,16 @@ private ConcurrentDictionary BuildInternalSdkEventStatus statuses.TryAdd(SdkInternalEvent.FlagsUpdated, false); return statuses; } + + private ConcurrentDictionary BuildSdkEventStatus() + { + ConcurrentDictionary statuses = new ConcurrentDictionary(); + statuses.TryAdd(SdkEvent.SdkReady, false); + statuses.TryAdd(SdkEvent.SdkUpdate, false); + statuses.TryAdd(SdkEvent.SdkReadyTimeout, false); + return statuses; + } + private EventHandler GetEventHandler(SdkInternalEvent sdkInternalEvent) { switch (sdkInternalEvent) @@ -156,6 +127,18 @@ private EventHandler GetEventHandler(SdkInternalEvent sdkInternal return null; } + + private EventHandler GetPublicEventHandler(SdkEvent sdkEvent) + { + switch (sdkEvent) + { + case SdkEvent.SdkReady: return PublicSdkReadyHandler; + case SdkEvent.SdkReadyTimeout: return PublicSdkTimedOutHandler; + case SdkEvent.SdkUpdate: return PublicSdkUpdateHandler; + } + + return null; + } #endregion } } diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs deleted file mode 100644 index c7d46587..00000000 --- a/src/Splitio/Services/Common/IEventDelivery.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Splitio.Domain; - -namespace Splitio.Services.Common -{ - public interface IEventDelivery - { - void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata); - } -} diff --git a/src/Splitio/Services/Common/IEventHandler.cs b/src/Splitio/Services/Common/IEventHandler.cs index 414473f0..91bbdbd2 100644 --- a/src/Splitio/Services/Common/IEventHandler.cs +++ b/src/Splitio/Services/Common/IEventHandler.cs @@ -1,9 +1,9 @@ -using Splitio.Domain; - + namespace Splitio.Services.Common { public interface IEventHandler { - void Handle(SdkEvent sdkEvent, EventMetadata eventMetadata); + void SubscribeInternalEvents(); + void ClearInternalEventsSubscription(); } } diff --git a/src/Splitio/Services/Common/QueuedSdkEventDto.cs b/src/Splitio/Services/Common/QueuedSdkEventDto.cs deleted file mode 100644 index b189a359..00000000 --- a/src/Splitio/Services/Common/QueuedSdkEventDto.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Splitio.Domain; -using System; - -namespace Splitio.Services.EventSource.Workers -{ - public class QueuedSdkEventDto - { - public SdkEvent SdkEvent { get; set; } - public EventMetadata EventMetadata { get; set; } - } -} diff --git a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs index fbc5f21b..0dc32194 100644 --- a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs +++ b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs @@ -24,11 +24,11 @@ public void TriggerAndCatchEventsTest() //Arrange EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); EventsManager eventsManager = new EventsManager(); - EventDelivery eventDelivery = new EventDelivery(eventsManager); - eventDelivery.Start(); - EventHandler eventHandler = new EventHandler(config, eventsManager, eventDelivery); - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + EventHandler eventHandler = new EventHandler(config, eventsManager); + eventHandler.SubscribeInternalEvents(); + + eventsManager.PublicSdkUpdateHandler += sdkUpdate_callback; + eventsManager.PublicSdkReadyHandler += sdkReady_callback; Dictionary metaData = new Dictionary { @@ -59,18 +59,15 @@ public void TriggerAndCatchEventsTest() Thread.Sleep(2000); Assert.IsTrue(_sdkUpdate); Assert.IsFalse(_sdkReady); - - eventDelivery.Stop(); - eventsManager.Destroy(); } - private void sdkUpdate_callback(EventMetadata metadata) + private void sdkUpdate_callback(object sender, EventMetadata metadata) { _sdkUpdate = true; _eventMetadata = metadata; } - private void sdkReady_callback(EventMetadata metadata) + private void sdkReady_callback(object sender, EventMetadata metadata) { _sdkReady = true; _eventMetadata = metadata; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs index 2c743ba0..4d784980 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs @@ -1,8 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; using Splitio.Domain; using Splitio.Services.Common; using System.Collections.Generic; +using System.Threading; using EventHandler = Splitio.Services.Common.EventHandler; namespace Splitio_Tests.Unit_Tests.Common @@ -10,6 +10,10 @@ namespace Splitio_Tests.Unit_Tests.Common [TestClass] public class EventHandlerTest { + private bool SdkReady = false; + private bool SdkTimedOut = false; + private bool SdkUpdate = false; + private EventMetadata eMetadata = null; [TestMethod] public void TriggerAndCatchEventsTest() @@ -17,10 +21,13 @@ public void TriggerAndCatchEventsTest() //Arrange EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); EventsManager eventsManager = new EventsManager(); - Mock eventDelivery = new Mock(); - EventHandler eventHandler = new EventHandler(config, eventsManager, eventDelivery.Object); - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + + EventHandler eventHandler = new EventHandler(config, eventsManager); + eventHandler.SubscribeInternalEvents(); + + eventsManager.PublicSdkUpdateHandler += sdkUpdate_callback; + eventsManager.PublicSdkReadyHandler += sdkReady_callback; + eventsManager.PublicSdkTimedOutHandler += sdkTimedOut_callback; Dictionary metaData = new Dictionary { @@ -30,32 +37,116 @@ public void TriggerAndCatchEventsTest() eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, eventMetadata); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, eventMetadata); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, eventMetadata); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkTimedOut); - eventDelivery.Verify(mock => mock.Deliver(It.IsAny (), It.IsAny()), Times.Never); - + ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkReady, It.IsAny()), Times.Once); - eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkUpdate, It.IsAny()), Times.Never); - eventsManager.SetSdkEventTriggered(SdkEvent.SdkReady); + Thread.Sleep(500); + Assert.IsTrue(SdkReady); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkTimedOut); + VerifyMetadata(eMetadata); - eventDelivery.Reset(); + ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkUpdate, It.IsAny()), Times.Once); - eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkReady, It.IsAny()), Times.Never); - eventsManager.SetSdkEventTriggered(SdkEvent.SdkUpdate); + Thread.Sleep(500); + Assert.IsTrue(SdkUpdate); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkTimedOut); + VerifyMetadata(eMetadata); - eventDelivery.Reset(); + ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkUpdate, It.IsAny()), Times.Once); - eventDelivery.Verify(mock => mock.Deliver(SdkEvent.SdkReady, It.IsAny()), Times.Never); + Thread.Sleep(500); + Assert.IsTrue(SdkUpdate); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkTimedOut); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + Thread.Sleep(500); + Assert.IsTrue(SdkUpdate); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkTimedOut); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + Thread.Sleep(500); + Assert.IsTrue(SdkUpdate); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkTimedOut); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + Thread.Sleep(500); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkReady); + Assert.IsTrue(SdkTimedOut); + VerifyMetadata(eMetadata); + } + + [TestMethod] + public void SubscribeInternalEventsTest() + { + //Arrange + EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + EventsManager eventsManager = new EventsManager(); + + EventHandler eventHandler = new EventHandler(config, eventsManager); + eventsManager.PublicSdkTimedOutHandler += sdkTimedOut_callback; + EventMetadata eventMetadata = new EventMetadata(new Dictionary()); + + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, eventMetadata); + Assert.IsFalse(SdkTimedOut); + + SdkTimedOut = false; + eventHandler.SubscribeInternalEvents(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, eventMetadata); + Assert.IsTrue(SdkTimedOut); + + SdkTimedOut = false; + eventHandler.ClearInternalEventsSubscription(); + eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, eventMetadata); + Assert.IsFalse(SdkTimedOut); + } + + void ResetAllVariables() + { + SdkReady = false; + SdkTimedOut = false; + eMetadata = null; + SdkUpdate = false; + } + + void VerifyMetadata(EventMetadata eMetdata) + { + Assert.IsTrue(eMetadata.ContainKey("flags")); + List flags = (List)eMetadata.GetData()["flags"]; + Assert.IsTrue(flags.Count == 1); + Assert.IsTrue(flags.Contains("flag1")); + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + eMetadata = metadata; } - private void sdkUpdate_callback(EventMetadata metadata) + private void sdkReady_callback(object sender, EventMetadata metadata) { + SdkReady = true; + eMetadata = metadata; } - private void sdkReady_callback(EventMetadata metadata) + private void sdkTimedOut_callback(object sender, EventMetadata metadata) { + SdkTimedOut = true; + eMetadata = metadata; } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 97e4a945..03293c9c 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -15,6 +15,7 @@ public class EventsManagerTests private bool SegmentsUpdated = false; private bool SdkReady = false; private bool SdkTimedOut = false; + private bool SdkUpdate = false; private EventMetadata eMetadata = null; [TestMethod] @@ -29,6 +30,10 @@ public void TestFiringInternalEvents() eventsManager.SdkReadyHandler += EventManager_SdkReadyHandler; eventsManager.SdkTimedOutHandler += EventManager_SdkTimedOutHandler; + eventsManager.PublicSdkReadyHandler += sdkReady_callback; + eventsManager.PublicSdkUpdateHandler += sdkUpdate_callback; + eventsManager.PublicSdkTimedOutHandler += sdkTimedOut_callback; + Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } @@ -68,36 +73,27 @@ public void TestFiringInternalEvents() Thread.Sleep(1000); Assert.IsTrue(SegmentsUpdated); VerifyMetadata(eMetadata); - } - [TestMethod] - public void TestRegisterEvents() - { - EventsManager eventsManager = new EventsManager(); - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); - - Assert.IsFalse(eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)); - Assert.IsFalse(eventsManager.EventAlreadyTriggered(SdkEvent.SdkUpdate)); - Assert.IsTrue(eventsManager.IsEventRegistered(SdkEvent.SdkUpdate)); - Assert.IsTrue(eventsManager.IsEventRegistered(SdkEvent.SdkReady)); - Assert.IsFalse(eventsManager.IsEventRegistered(SdkEvent.SdkReadyTimeout)); - Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkUpdate) == sdkUpdate_callback); - Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkReady) == sdkReady_callback); - Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkReadyTimeout) == null); - - eventsManager.SetSdkEventTriggered(SdkEvent.SdkReady); - Assert.IsTrue(eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)); - Assert.IsFalse(eventsManager.EventAlreadyTriggered(SdkEvent.SdkUpdate)); - - eventsManager.Unregister(SdkEvent.SdkUpdate); - Assert.IsFalse(eventsManager.IsEventRegistered(SdkEvent.SdkUpdate)); - Assert.IsTrue(eventsManager.GetCallbackAction(SdkEvent.SdkUpdate) == null); - - eventsManager.Destroy(); - Assert.IsFalse(eventsManager.IsEventRegistered(SdkEvent.SdkReady)); + ResetAllVariables(); + eventsManager.OnSdkEvent(SdkEvent.SdkReady, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(SdkReady); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkEvent(SdkEvent.SdkUpdate, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(SdkUpdate); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.OnSdkEvent(SdkEvent.SdkReadyTimeout, new EventMetadata(metaData)); + Thread.Sleep(1000); + Assert.IsTrue(SdkTimedOut); + VerifyMetadata(eMetadata); } + [TestMethod] public void TestEventsStatus() { @@ -108,6 +104,9 @@ public void TestEventsStatus() Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated)); Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut)); Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated)); + Assert.IsFalse(eventsManager.GetSdkEventStatus(SdkEvent.SdkReady)); + Assert.IsFalse(eventsManager.GetSdkEventStatus(SdkEvent.SdkUpdate)); + Assert.IsFalse(eventsManager.GetSdkEventStatus(SdkEvent.SdkReadyTimeout)); eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, true); Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); @@ -129,6 +128,15 @@ public void TestEventsStatus() eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, false); Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); + + eventsManager.UpdateSdkEventStatus(SdkEvent.SdkReady, true); + Assert.IsTrue(eventsManager.GetSdkEventStatus(SdkEvent.SdkReady)); + + eventsManager.UpdateSdkEventStatus(SdkEvent.SdkUpdate, true); + Assert.IsTrue(eventsManager.GetSdkEventStatus(SdkEvent.SdkUpdate)); + + eventsManager.UpdateSdkEventStatus(SdkEvent.SdkReadyTimeout, true); + Assert.IsTrue(eventsManager.GetSdkEventStatus(SdkEvent.SdkReadyTimeout)); } void ResetAllVariables() @@ -140,7 +148,9 @@ void ResetAllVariables() SdkReady = false; SdkTimedOut = false; eMetadata = null; + SdkUpdate = false; } + void VerifyMetadata(EventMetadata eMetdata) { Assert.IsTrue(eMetadata.ContainKey("flags")); @@ -185,14 +195,22 @@ void EventManager_SdkTimedOutHandler(object sender, EventMetadata eventMetadata) eMetadata = eventMetadata; } - private void sdkUpdate_callback(EventMetadata metadata) + private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkReady = true; + SdkUpdate = true; + eMetadata = metadata; } - private void sdkReady_callback(EventMetadata metadata) + private void sdkReady_callback(object sender, EventMetadata metadata) { SdkReady = true; + eMetadata = metadata; + } + + private void sdkTimedOut_callback(object sender, EventMetadata metadata) + { + SdkTimedOut = true; + eMetadata = metadata; } } } From 37874f18ca336ce6eaf490f526721b735454885c Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 13:32:58 -0800 Subject: [PATCH 11/87] updated requirement for sdkready event --- src/Splitio/Domain/EventsManagerConfig.cs | 3 --- .../Unit Tests/Common/EventsManagerConfigTests.cs | 6 ++---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 44583f8d..45ca4163 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -31,9 +31,6 @@ public static EventsManagerConfig BuildEventsManagerConfig() { SdkEvent.SdkReady, new HashSet { - SdkInternalEvent.RuleBasedSegmentsUpdated, - SdkInternalEvent.FlagsUpdated, - SdkInternalEvent.SegmentsUpdated, SdkInternalEvent.SdkReady } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index 5738adeb..18693c79 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -15,10 +15,8 @@ public void BuildInstance() //Assert config.RequireAll.TryGetValue(SdkEvent.SdkReady, out var require1); - Assert.AreEqual(4, require1.Count); - Assert.IsTrue(require1.Contains(SdkInternalEvent.SegmentsUpdated)); - Assert.IsTrue(require1.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); - Assert.IsTrue(require1.Contains(SdkInternalEvent.FlagsUpdated)); + Assert.AreEqual(1, require1.Count); + Assert.IsTrue(require1.Contains(SdkInternalEvent.SdkReady)); config.Prerequisites.TryGetValue(SdkEvent.SdkUpdate, out var ready2); Assert.IsTrue(ready2.Contains(SdkInternalEvent.SdkReady)); From b92e3ab5d2c30bea72f7e7c5a6f1a700c61514d2 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 13:40:07 -0800 Subject: [PATCH 12/87] updated IEventManager interface --- src/Splitio/Services/Common/EventsManager.cs | 2 +- src/Splitio/Services/Common/IEventsManager.cs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index d00280ef..11b5edbf 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -6,7 +6,7 @@ namespace Splitio.Services.Common { - public class EventsManager + public class EventsManager : IEventsManager { ConcurrentDictionary _eventsStatus; ConcurrentDictionary _internalEventsStatus; diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index 086cb9f1..cbf5e17a 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -5,9 +5,7 @@ namespace Splitio.Services.Common { public interface IEventsManager { - bool EventAlreadyTriggered(SdkEvent sdkEvent); - void Register(SdkEvent sdkEvent, Action callbackAction); - void Unregister(SdkEvent sdkEvent); - void Destroy(); + void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); + void OnSdkEvent(SdkEvent sdkEvent, EventMetadata eventMetadata); } } From e342316966d5fc645e0613dee561502987347b5e Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 14:21:50 -0800 Subject: [PATCH 13/87] polishing --- src/Splitio/Services/Common/IEventsManager.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index cbf5e17a..7a0000d9 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,5 +1,4 @@ using Splitio.Domain; -using System; namespace Splitio.Services.Common { From 750d854edc83d0d366f2707fc557bf09499d0ed0 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 15:35:32 -0800 Subject: [PATCH 14/87] polis --- src/Splitio/Domain/EventMetadata.cs | 11 ++++------ src/Splitio/Services/Common/EventHandler.cs | 22 +++++++++---------- src/Splitio/Services/Common/EventsManager.cs | 8 +++---- .../Integration Tests/SdkEventsTest.cs | 6 ++--- .../Unit Tests/Common/EventHandlerTest.cs | 13 ++++++----- .../Unit Tests/Common/EventMetadataTests.cs | 2 +- .../Unit Tests/Common/EventsManagerTests.cs | 19 ++++++++-------- 7 files changed, 39 insertions(+), 42 deletions(-) diff --git a/src/Splitio/Domain/EventMetadata.cs b/src/Splitio/Domain/EventMetadata.cs index 7847c670..f0d356ea 100644 --- a/src/Splitio/Domain/EventMetadata.cs +++ b/src/Splitio/Domain/EventMetadata.cs @@ -6,7 +6,7 @@ namespace Splitio.Domain { public class EventMetadata { - private Dictionary _data; + private readonly Dictionary _data; public EventMetadata(Dictionary data) { @@ -27,18 +27,15 @@ public bool ContainKey(string key) private Dictionary Santize(Dictionary data) { Dictionary santizedData = new Dictionary(); - foreach (var item in data) + foreach (var item in data.Where(x => ValueIsValid(x.Value))) { - if (ValueIsValid(item.Value)) - { - santizedData.Add(item.Key, item.Value); - } + santizedData.Add(item.Key, item.Value); } return santizedData; } - private bool ValueIsValid(object value) + private static bool ValueIsValid(object value) { if (!(value is null) && (PropertiesValidator.IsNumeric(value) || (value is bool) || (value is string) || (value is List))) { diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index 48b0926b..df73f978 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -2,6 +2,7 @@ using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System.Collections.Generic; +using System.Linq; namespace Splitio.Services.Common { @@ -9,8 +10,8 @@ namespace Splitio.Services.Common public class EventHandler : IEventHandler { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventHandler"); - EventsManagerConfig _config; - EventsManager _eventsManager; + private readonly EventsManagerConfig _config; + private readonly EventsManager _eventsManager; struct ValidSdkEvent { public SdkEvent sdkEvent; @@ -125,11 +126,11 @@ private bool CheckPrerequisites(SdkEvent sdkEvent) { if (kvp.Key == sdkEvent) { - foreach (var val in kvp.Value) + foreach (var val in kvp.Value.Where(x => !_eventsManager.GetSdkInternalEventStatus(x))) { - if (!_eventsManager.GetSdkInternalEventStatus(val)) - return false; + return false; } + return true; } } @@ -153,14 +154,11 @@ private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; foreach (KeyValuePair> kvp in _config.RequireAny) { - foreach (var val in kvp.Value) + foreach (var val in kvp.Value.Where(x => x == sdkInternalEvent)) { - if (val == sdkInternalEvent) - { - validSdkEvent.valid = true; - validSdkEvent.sdkEvent = kvp.Key; - return validSdkEvent; - } + validSdkEvent.valid = true; + validSdkEvent.sdkEvent = kvp.Key; + return validSdkEvent; } } diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 11b5edbf..4caf6c3a 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -8,8 +8,8 @@ namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - ConcurrentDictionary _eventsStatus; - ConcurrentDictionary _internalEventsStatus; + private readonly ConcurrentDictionary _eventsStatus; + private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); public event EventHandler RuleBasedSegmentsUpdatedHandler; @@ -92,7 +92,7 @@ public virtual void OnSdkEvent(SdkEvent sdkEvent, EventMetadata eventMetadata) #endregion #region Private Methods - private ConcurrentDictionary BuildInternalSdkEventStatus() + private static ConcurrentDictionary BuildInternalSdkEventStatus() { ConcurrentDictionary statuses = new ConcurrentDictionary(); statuses.TryAdd(SdkInternalEvent.SdkReady, false); @@ -104,7 +104,7 @@ private ConcurrentDictionary BuildInternalSdkEventStatus return statuses; } - private ConcurrentDictionary BuildSdkEventStatus() + private static ConcurrentDictionary BuildSdkEventStatus() { ConcurrentDictionary statuses = new ConcurrentDictionary(); statuses.TryAdd(SdkEvent.SdkReady, false); diff --git a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs index 0dc32194..42dbbf31 100644 --- a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs +++ b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs @@ -43,20 +43,20 @@ public void TriggerAndCatchEventsTest() Assert.IsFalse(_sdkReady); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData2)); - Thread.Sleep(2000); + System.Threading.SpinWait.SpinUntil(() => _sdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(_sdkReady); Assert.IsFalse(_sdkUpdate); _sdkReady = false; _sdkUpdate = false; eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Thread.Sleep(2000); + System.Threading.SpinWait.SpinUntil(() => _sdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(_sdkUpdate); Assert.IsFalse(_sdkReady); _sdkUpdate = false; eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - Thread.Sleep(2000); + System.Threading.SpinWait.SpinUntil(() => _sdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(_sdkUpdate); Assert.IsFalse(_sdkReady); } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs index 4d784980..12a6dde9 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Common; +using System; using System.Collections.Generic; using System.Threading; using EventHandler = Splitio.Services.Common.EventHandler; @@ -43,7 +44,7 @@ public void TriggerAndCatchEventsTest() ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - Thread.Sleep(500); + System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); @@ -51,7 +52,7 @@ public void TriggerAndCatchEventsTest() ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Thread.Sleep(500); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkUpdate); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkTimedOut); @@ -59,7 +60,7 @@ public void TriggerAndCatchEventsTest() ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - Thread.Sleep(500); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkUpdate); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkTimedOut); @@ -67,7 +68,7 @@ public void TriggerAndCatchEventsTest() ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - Thread.Sleep(500); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkUpdate); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkTimedOut); @@ -75,7 +76,7 @@ public void TriggerAndCatchEventsTest() ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - Thread.Sleep(500); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkUpdate); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkTimedOut); @@ -83,7 +84,7 @@ public void TriggerAndCatchEventsTest() ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - Thread.Sleep(500); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkReady); Assert.IsTrue(SdkTimedOut); diff --git a/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs index dfcba68b..057eb708 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs @@ -32,7 +32,7 @@ public void InstanceWithSantizeInput() result.GetData().TryGetValue("strValue", out var svalue); Assert.AreEqual(10, timeout); - Assert.AreEqual(true, bvalue); + Assert.IsTrue((bool)bvalue); Assert.AreEqual("value", svalue); Assert.IsTrue(featureList.Count == 1); Assert.IsTrue(featureList.Contains("feature1")); diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 03293c9c..fc631f32 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Common; +using System; using System.Collections.Generic; using System.Threading; @@ -40,55 +41,55 @@ public void TestFiringInternalEvents() }; eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => RuleBasedSegmentsUpdated, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(RuleBasedSegmentsUpdated); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => FlagKilledNotification, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(FlagKilledNotification); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkTimedOut); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => FlagsUpdated, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(FlagsUpdated); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => SegmentsUpdated, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SegmentsUpdated); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkEvent(SdkEvent.SdkReady, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkEvent(SdkEvent.SdkUpdate, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkUpdate); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.OnSdkEvent(SdkEvent.SdkReadyTimeout, new EventMetadata(metaData)); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkTimedOut); VerifyMetadata(eMetadata); } From f2d005abf58ba32683380210195ca11f198cc433 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 20:02:15 -0800 Subject: [PATCH 15/87] polish --- src/Splitio/Domain/EventMetadata.cs | 2 +- src/Splitio/Services/Common/EventHandler.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Splitio/Domain/EventMetadata.cs b/src/Splitio/Domain/EventMetadata.cs index f0d356ea..67441887 100644 --- a/src/Splitio/Domain/EventMetadata.cs +++ b/src/Splitio/Domain/EventMetadata.cs @@ -24,7 +24,7 @@ public bool ContainKey(string key) return _data.ContainsKey(key); } - private Dictionary Santize(Dictionary data) + private static Dictionary Santize(Dictionary data) { Dictionary santizedData = new Dictionary(); foreach (var item in data.Where(x => ValueIsValid(x.Value))) diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index df73f978..cfa5af76 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -126,7 +126,7 @@ private bool CheckPrerequisites(SdkEvent sdkEvent) { if (kvp.Key == sdkEvent) { - foreach (var val in kvp.Value.Where(x => !_eventsManager.GetSdkInternalEventStatus(x))) + if (kvp.Value.Where(x => !_eventsManager.GetSdkInternalEventStatus(x)).Count() > 0) { return false; } @@ -154,7 +154,7 @@ private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; foreach (KeyValuePair> kvp in _config.RequireAny) { - foreach (var val in kvp.Value.Where(x => x == sdkInternalEvent)) + if (kvp.Value.Where(x => x == sdkInternalEvent).Count() > 0) { validSdkEvent.valid = true; validSdkEvent.sdkEvent = kvp.Key; From d5e2332dc060d989c2381599203383d4ccacbc31 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany Date: Thu, 11 Dec 2025 04:07:02 +0000 Subject: [PATCH 16/87] Update pipeline dotnet-client-repo --- .harness/pipeline.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.harness/pipeline.yaml b/.harness/pipeline.yaml index 83dee830..67fab5ef 100644 --- a/.harness/pipeline.yaml +++ b/.harness/pipeline.yaml @@ -268,7 +268,7 @@ pipeline: -CommitSha "<+codebase.commitSha>" ` -SonarProjectKey "dotnet-client" ` -SonarToken "<+secrets.getValue('sonarqube-token')>" ` - -SonarUrl "https://sonar.harness.io/" + -SonarUrl "https://sonar.harness.io" - parallel: - step: type: Run From a36a11fa248e567e28ae4b76125304629e954d66 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 20:17:42 -0800 Subject: [PATCH 17/87] polish --- src/Splitio/Services/Common/EventHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index cfa5af76..da4e3567 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -126,7 +126,7 @@ private bool CheckPrerequisites(SdkEvent sdkEvent) { if (kvp.Key == sdkEvent) { - if (kvp.Value.Where(x => !_eventsManager.GetSdkInternalEventStatus(x)).Count() > 0) + if (kvp.Value.Count(x => !_eventsManager.GetSdkInternalEventStatus(x)) > 0) { return false; } @@ -154,7 +154,7 @@ private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; foreach (KeyValuePair> kvp in _config.RequireAny) { - if (kvp.Value.Where(x => x == sdkInternalEvent).Count() > 0) + if (kvp.Value.Count(x => x == sdkInternalEvent) > 0) { validSdkEvent.valid = true; validSdkEvent.sdkEvent = kvp.Key; From d899bdc502745f2ae6809bf2147e232ffc68177f Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 20:27:31 -0800 Subject: [PATCH 18/87] polish --- src/Splitio/Services/Common/EventHandler.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index da4e3567..19b2f4e8 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -126,7 +126,7 @@ private bool CheckPrerequisites(SdkEvent sdkEvent) { if (kvp.Key == sdkEvent) { - if (kvp.Value.Count(x => !_eventsManager.GetSdkInternalEventStatus(x)) > 0) + if (kvp.Value.Any(x => !_eventsManager.GetSdkInternalEventStatus(x))) { return false; } @@ -154,7 +154,7 @@ private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; foreach (KeyValuePair> kvp in _config.RequireAny) { - if (kvp.Value.Count(x => x == sdkInternalEvent) > 0) + if (kvp.Value.Any(x => x == sdkInternalEvent)) { validSdkEvent.valid = true; validSdkEvent.sdkEvent = kvp.Key; From 5dd4ee7dfd969e7bed7bf68b4b1c35bf078a0a3b Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 10 Dec 2025 20:41:49 -0800 Subject: [PATCH 19/87] polish --- src/Splitio/Services/Common/EventHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs index 19b2f4e8..b018ffd1 100644 --- a/src/Splitio/Services/Common/EventHandler.cs +++ b/src/Splitio/Services/Common/EventHandler.cs @@ -154,7 +154,7 @@ private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; foreach (KeyValuePair> kvp in _config.RequireAny) { - if (kvp.Value.Any(x => x == sdkInternalEvent)) + if (kvp.Value.Contains(sdkInternalEvent)) { validSdkEvent.valid = true; validSdkEvent.sdkEvent = kvp.Key; From 391258bc34ab82b91828267b6a4e2d2c6a2616fe Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 11 Dec 2025 15:08:05 -0800 Subject: [PATCH 20/87] Removed internal event subscriptions, moved handler logic to manager. --- src/Splitio/Domain/EventsManagerConfig.cs | 10 +- src/Splitio/Services/Common/EventDelivery.cs | 28 ++ src/Splitio/Services/Common/EventHandler.cs | 205 -------------- src/Splitio/Services/Common/EventsManager.cs | 257 ++++++++++++------ src/Splitio/Services/Common/IEventDelivery.cs | 10 + src/Splitio/Services/Common/IEventHandler.cs | 9 - src/Splitio/Services/Common/IEventsManager.cs | 6 +- .../Integration Tests/SdkEventsTest.cs | 76 ------ .../Unit Tests/Common/EventDeliveryTests.cs | 49 ++++ .../Unit Tests/Common/EventHandlerTest.cs | 153 ----------- .../Common/EventsManagerConfigTests.cs | 2 +- .../Unit Tests/Common/EventsManagerTests.cs | 180 ++++-------- 12 files changed, 331 insertions(+), 654 deletions(-) create mode 100644 src/Splitio/Services/Common/EventDelivery.cs delete mode 100644 src/Splitio/Services/Common/EventHandler.cs create mode 100644 src/Splitio/Services/Common/IEventDelivery.cs delete mode 100644 src/Splitio/Services/Common/IEventHandler.cs delete mode 100644 tests/Splitio-tests/Integration Tests/SdkEventsTest.cs create mode 100644 tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs delete mode 100644 tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 45ca4163..86de75cb 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -6,14 +6,14 @@ public class EventsManagerConfig { public Dictionary> RequireAll { get; private set; } public Dictionary> RequireAny { get; private set; } - public Dictionary> Prerequisites { get; private set; } + public Dictionary> Prerequisites { get; private set; } public Dictionary> SuppressedBy { get; private set; } public Dictionary ExecutionLimits { get; private set; } private EventsManagerConfig( Dictionary> requireAll, Dictionary> requireAny, - Dictionary> prerequisites, + Dictionary> prerequisites, Dictionary> suppressedBy, Dictionary executionLimits) { @@ -36,12 +36,12 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; - Dictionary> prerequisites = new Dictionary> + Dictionary> prerequisites = new Dictionary> { { - SdkEvent.SdkUpdate, new HashSet + SdkEvent.SdkUpdate, new HashSet { - SdkInternalEvent.SdkReady + SdkEvent.SdkReady } } }; diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs new file mode 100644 index 00000000..4c59e21d --- /dev/null +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -0,0 +1,28 @@ +using Splitio.Domain; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; +using System; + +namespace Splitio.Services.Common +{ + public class EventDelivery : IEventDelivery + { + private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); + + public virtual void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata, EventHandler handler) + { + if (handler != null) + { + _logger.Debug($"EventManager: Triggering handle for Sdk Event {sdkEvent}"); + try + { + handler(this, eventMetadata); + } + catch (Exception e) + { + _logger.Error($"EventManager: Failed to run event {sdkEvent} handler {e.Message}", e); + } + } + } + } +} diff --git a/src/Splitio/Services/Common/EventHandler.cs b/src/Splitio/Services/Common/EventHandler.cs deleted file mode 100644 index b018ffd1..00000000 --- a/src/Splitio/Services/Common/EventHandler.cs +++ /dev/null @@ -1,205 +0,0 @@ -using Splitio.Domain; -using Splitio.Services.Logger; -using Splitio.Services.Shared.Classes; -using System.Collections.Generic; -using System.Linq; - -namespace Splitio.Services.Common -{ - - public class EventHandler : IEventHandler - { - private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventHandler"); - private readonly EventsManagerConfig _config; - private readonly EventsManager _eventsManager; - struct ValidSdkEvent - { - public SdkEvent sdkEvent; - public bool valid; - } - - #region Public Methods - public EventHandler(EventsManagerConfig eventsManagerConfig, EventsManager eventsManager) - { - _config = eventsManagerConfig; - _eventsManager = eventsManager; - } - - public void SubscribeInternalEvents() - { - _eventsManager.RuleBasedSegmentsUpdatedHandler += EventManager_RuleBasedSegmentsUpdatedHandler; - _eventsManager.FlagKilledNotificationHandler += EventManager_FlagKilledNotificationHandler; - _eventsManager.FlagsUpdatedHandler += EventManager_FlagsUpdatedHandler; - _eventsManager.SegmentsUpdatedHandler += EventManager_SegmentsUpdatedHandler; - _eventsManager.SdkReadyHandler += EventManager_SdkReadyHandler; - _eventsManager.SdkTimedOutHandler += EventManager_SdkTimedOutHandler; - _logger.Debug("EventHandler: Subscription to internal events are added."); - } - - public void ClearInternalEventsSubscription() - { - _eventsManager.RuleBasedSegmentsUpdatedHandler -= EventManager_RuleBasedSegmentsUpdatedHandler; - _eventsManager.FlagKilledNotificationHandler -= EventManager_FlagKilledNotificationHandler; - _eventsManager.FlagsUpdatedHandler -= EventManager_FlagsUpdatedHandler; - _eventsManager.SegmentsUpdatedHandler -= EventManager_SegmentsUpdatedHandler; - _eventsManager.SdkReadyHandler -= EventManager_SdkReadyHandler; - _eventsManager.SdkTimedOutHandler -= EventManager_SdkTimedOutHandler; - _logger.Debug("EventHandler: Subscription to internal events are removed."); - } - #endregion - - #region Private Methods - private void HandleInternalEvent(EventMetadata eventMetadata, SdkInternalEvent sdkInternalEvent) - { - _logger.Debug($"EventHandler: Handling internal event {sdkInternalEvent}"); - ValidSdkEvent eventToNotify = GetSdkEventIfApplicable(sdkInternalEvent); - if (eventToNotify.valid) - { - _logger.Debug($"EventHandler: Firing Sdk event {eventToNotify.sdkEvent}"); - _eventsManager.OnSdkEvent(eventToNotify.sdkEvent, eventMetadata); - _eventsManager.UpdateSdkEventStatus(eventToNotify.sdkEvent, true); - } - - foreach (SdkEvent sdkEvent in CheckRequireAll()) - { - _logger.Debug($"EventHandler: Firing Sdk event {sdkEvent}"); - _eventsManager.OnSdkEvent(sdkEvent, eventMetadata); - _eventsManager.UpdateSdkEventStatus(sdkEvent, true); - } - } - - private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) - { - ValidSdkEvent finalSdkEvent; - finalSdkEvent.valid = false; - finalSdkEvent.sdkEvent = SdkEvent.SdkUpdate; - - ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); - if (!requireAnySdkEvent.valid) - { - _logger.Debug($"EventHandler: No Event available for internal event {sdkInternalEvent}"); - return requireAnySdkEvent; - } - - if (requireAnySdkEvent.valid && !_eventsManager.GetSdkEventStatus(requireAnySdkEvent.sdkEvent) - && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) - { - _logger.Debug($"EventHandler: Detected Event {requireAnySdkEvent.sdkEvent} is available for internal event {sdkInternalEvent}"); - finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; - } - - finalSdkEvent.valid = CheckPrerequisites(finalSdkEvent.sdkEvent); - if (finalSdkEvent.valid) - { - _logger.Debug($"EventHandler: Event {requireAnySdkEvent.sdkEvent} is eligable for notification."); - } - return finalSdkEvent; - } - - private List CheckRequireAll() - { - List events = new List(); - foreach (KeyValuePair> kvp in _config.RequireAll) - { - bool finalStatus = true; - foreach (var val in kvp.Value) - { - finalStatus &= _eventsManager.GetSdkInternalEventStatus(val); - } - if (finalStatus - && CheckPrerequisites(kvp.Key) - && ((ExecutionLimit(kvp.Key) == 1 && !_eventsManager.GetSdkEventStatus(kvp.Key)) - || (ExecutionLimit(kvp.Key) == -1)) - && kvp.Value.Count > 0) - { - _logger.Debug($"EventHandler: Event {kvp.Key} is eligable as require all for notification."); - events.Add(kvp.Key); - } - } - - return events; - } - - private bool CheckPrerequisites(SdkEvent sdkEvent) - { - foreach (KeyValuePair> kvp in _config.Prerequisites) - { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => !_eventsManager.GetSdkInternalEventStatus(x))) - { - return false; - } - - return true; - } - } - - return true; - } - - private int ExecutionLimit(SdkEvent sdkEvent) - { - if (!_config.ExecutionLimits.ContainsKey(sdkEvent)) - return -1; - - _config.ExecutionLimits.TryGetValue(sdkEvent, out int limit); - return limit; - } - - private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) - { - ValidSdkEvent validSdkEvent; - validSdkEvent.valid = false; - validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; - foreach (KeyValuePair> kvp in _config.RequireAny) - { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.valid = true; - validSdkEvent.sdkEvent = kvp.Key; - return validSdkEvent; - } - } - - return validSdkEvent; - } - - void EventManager_RuleBasedSegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) - { - _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, true); - HandleInternalEvent(eventMetadata, SdkInternalEvent.RuleBasedSegmentsUpdated); - } - - void EventManager_FlagsUpdatedHandler(object sender, EventMetadata eventMetadata) - { - _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, true); - HandleInternalEvent(eventMetadata, SdkInternalEvent.FlagsUpdated); - } - - void EventManager_FlagKilledNotificationHandler(object sender, EventMetadata eventMetadata) - { - _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, true); - HandleInternalEvent(eventMetadata, SdkInternalEvent.FlagKilledNotification); - } - - void EventManager_SegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) - { - _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, true); - HandleInternalEvent(eventMetadata, SdkInternalEvent.SegmentsUpdated); - } - - void EventManager_SdkReadyHandler(object sender, EventMetadata eventMetadata) - { - _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, true); - HandleInternalEvent(eventMetadata, SdkInternalEvent.SdkReady); - } - - void EventManager_SdkTimedOutHandler(object sender, EventMetadata eventMetadata) - { - _eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, true); - HandleInternalEvent(eventMetadata, SdkInternalEvent.SdkTimedOut); - } - #endregion - } -} diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 4caf6c3a..1f921cd6 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -3,95 +3,139 @@ using Splitio.Services.Shared.Classes; using System; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - private readonly ConcurrentDictionary _eventsStatus; + ConcurrentDictionary> _activeEvents; + string Triggered = "Triggered"; + string EventHandler = "EventHandler"; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); + private readonly EventsManagerConfig _config; + private readonly EventDelivery _eventDelivery; + private readonly object _lock = new object(); + struct ValidSdkEvent + { + public SdkEvent sdkEvent; + public bool valid; + } - public event EventHandler RuleBasedSegmentsUpdatedHandler; - public event EventHandler FlagsUpdatedHandler; - public event EventHandler FlagKilledNotificationHandler; - public event EventHandler SegmentsUpdatedHandler; - public event EventHandler SdkReadyHandler; - public event EventHandler SdkTimedOutHandler; - - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; - - #region Public Methods public EventsManager() { - _eventsStatus = BuildSdkEventStatus(); + _activeEvents = new ConcurrentDictionary>(); _internalEventsStatus = BuildInternalSdkEventStatus(); + _config = EventsManagerConfig.BuildEventsManagerConfig(); + _eventDelivery = new EventDelivery(); } - public void UpdateSdkEventStatus(SdkEvent sdkEvent, bool status) + #region Public Methods + public void Register(SdkEvent sdkEvent, EventHandler handler) { - _eventsStatus.AddOrUpdate(sdkEvent, status, - (_, oldValue) => status); - _logger.Debug($"EventManager: Sdk Event {sdkEvent} status is updated to {status}"); + _activeEvents.TryGetValue(sdkEvent, out var dict); + if (dict == null) + { + _activeEvents.TryAdd(sdkEvent, new Dictionary() + { + {Triggered, false}, + {EventHandler, handler} + }); + _logger.Debug($"EventManager: Event {sdkEvent} is registered"); + } } - public bool GetSdkEventStatus(SdkEvent sdkEvent) + public void Unregister(SdkEvent sdkEvent) { - _eventsStatus.TryGetValue(sdkEvent, out var status); - return status; + if (_activeEvents.ContainsKey(sdkEvent)) + { + if (_activeEvents.TryGetValue(sdkEvent, out var dict)) + { + if (dict.Count > 0) + { + _activeEvents.TryRemove(sdkEvent, out _); + } + } + } } - public void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) + public void NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) { - _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, - (_, oldValue) => status); - _logger.Debug($"EventManager: Internal Event {sdkInternalEvent} status is updated to {status}"); + lock (_lock) + { + _logger.Debug($"EventHandler: Handling internal event {sdkInternalEvent}"); + UpdateSdkInternalEventStatus(sdkInternalEvent, true); + ValidSdkEvent eventToNotify = GetSdkEventIfApplicable(sdkInternalEvent); + if (eventToNotify.valid) + { + _logger.Debug($"EventHandler: Firing Sdk event {eventToNotify.sdkEvent}"); + _eventDelivery.Deliver(eventToNotify.sdkEvent, eventMetadata, GetEventHandler(eventToNotify.sdkEvent)); + SetSdkEventTriggered(eventToNotify.sdkEvent); + } + + foreach (SdkEvent sdkEvent in CheckRequireAll()) + { + _logger.Debug($"EventHandler: Firing Sdk event {sdkEvent}"); + _eventDelivery.Deliver(sdkEvent, eventMetadata, GetEventHandler(sdkEvent)); + SetSdkEventTriggered(sdkEvent); + } + } } + #endregion - public bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) - { - _internalEventsStatus.TryGetValue(sdkInternalEvent, out var status); - return status; + #region Private Methods + private void SetSdkEventTriggered(SdkEvent sdkEvent) + { + if (!_activeEvents.TryGetValue(sdkEvent, out var dict)) + { + return; + } + + if ((bool)dict[Triggered]) + { + return; + } + + Dictionary dict2 = new Dictionary(dict); + dict2[Triggered] = true; + _activeEvents.TryUpdate(sdkEvent, dict2, dict); } - public virtual void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) + private bool EventAlreadyTriggered(SdkEvent sdkEvent) { - EventHandler handler = GetEventHandler(sdkInternalEvent); - if (handler != null) + if (_activeEvents.TryGetValue(sdkEvent, out Dictionary triggered)) { - _logger.Debug($"EventManager: Triggering handle for Internal Event {sdkInternalEvent}"); - try - { - handler(this, eventMetadata); - } - catch (Exception e) - { - _logger.Error($"EventManager: Failed to run internal event {sdkInternalEvent} handler {e.Message}", e); - } + triggered.TryGetValue(Triggered, out var trig); + return (bool)trig; } + return false; } - public virtual void OnSdkEvent(SdkEvent sdkEvent, EventMetadata eventMetadata) + private EventHandler GetEventHandler(SdkEvent sdkEvent) { - EventHandler handler = GetPublicEventHandler(sdkEvent); - if (handler != null) + if (_activeEvents.TryGetValue(sdkEvent, out var dict)) { - _logger.Debug($"EventManager: Triggering handle for Sdk Event {sdkEvent}"); - try - { - handler(this, eventMetadata); - } - catch (Exception e) - { - _logger.Error($"EventManager: Failed to run event {sdkEvent} handler {e.Message}", e); - } + dict.TryGetValue(EventHandler, out var handler); + return (EventHandler)handler; } + return null; + } + + private void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) + { + _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, + (_, oldValue) => status); + _logger.Debug($"EventManager: Internal Event {sdkInternalEvent} status is updated to {status}"); + } + + private bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) + { + _internalEventsStatus.TryGetValue(sdkInternalEvent, out var status); + return status; } - #endregion - #region Private Methods private static ConcurrentDictionary BuildInternalSdkEventStatus() { ConcurrentDictionary statuses = new ConcurrentDictionary(); @@ -104,40 +148,101 @@ private static ConcurrentDictionary BuildInternalSdkEven return statuses; } - private static ConcurrentDictionary BuildSdkEventStatus() + private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) { - ConcurrentDictionary statuses = new ConcurrentDictionary(); - statuses.TryAdd(SdkEvent.SdkReady, false); - statuses.TryAdd(SdkEvent.SdkUpdate, false); - statuses.TryAdd(SdkEvent.SdkReadyTimeout, false); - return statuses; + ValidSdkEvent finalSdkEvent; + finalSdkEvent.valid = false; + finalSdkEvent.sdkEvent = SdkEvent.SdkUpdate; + + ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); + if (!requireAnySdkEvent.valid) + { + _logger.Debug($"EventHandler: No Event available for internal event {sdkInternalEvent}"); + return requireAnySdkEvent; + } + + if (requireAnySdkEvent.valid && !EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) + && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) + { + _logger.Debug($"EventHandler: Detected Event {requireAnySdkEvent.sdkEvent} is available for internal event {sdkInternalEvent}"); + finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; + } + + finalSdkEvent.valid = CheckPrerequisites(finalSdkEvent.sdkEvent); + if (finalSdkEvent.valid) + { + _logger.Debug($"EventHandler: Event {requireAnySdkEvent.sdkEvent} is eligable for notification."); + } + return finalSdkEvent; } - private EventHandler GetEventHandler(SdkInternalEvent sdkInternalEvent) + private List CheckRequireAll() { - switch (sdkInternalEvent) + List events = new List(); + foreach (KeyValuePair> kvp in _config.RequireAll) { - case SdkInternalEvent.RuleBasedSegmentsUpdated: return RuleBasedSegmentsUpdatedHandler; - case SdkInternalEvent.FlagsUpdated: return FlagsUpdatedHandler; - case SdkInternalEvent.FlagKilledNotification: return FlagKilledNotificationHandler; - case SdkInternalEvent.SegmentsUpdated: return SegmentsUpdatedHandler; - case SdkInternalEvent.SdkReady: return SdkReadyHandler; - case SdkInternalEvent.SdkTimedOut: return SdkTimedOutHandler; + bool finalStatus = true; + foreach (var val in kvp.Value) + { + finalStatus &= GetSdkInternalEventStatus(val); + } + if (finalStatus + && CheckPrerequisites(kvp.Key) + && ((ExecutionLimit(kvp.Key) == 1 && !EventAlreadyTriggered(kvp.Key)) + || (ExecutionLimit(kvp.Key) == -1)) + && kvp.Value.Count > 0) + { + _logger.Debug($"EventHandler: Event {kvp.Key} is eligable as require all for notification."); + events.Add(kvp.Key); + } } - return null; + return events; } - private EventHandler GetPublicEventHandler(SdkEvent sdkEvent) + private bool CheckPrerequisites(SdkEvent sdkEvent) { - switch (sdkEvent) + foreach (KeyValuePair> kvp in _config.Prerequisites) { - case SdkEvent.SdkReady: return PublicSdkReadyHandler; - case SdkEvent.SdkReadyTimeout: return PublicSdkTimedOutHandler; - case SdkEvent.SdkUpdate: return PublicSdkUpdateHandler; + if (kvp.Key == sdkEvent) + { + if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } } - return null; + return true; + } + + private int ExecutionLimit(SdkEvent sdkEvent) + { + if (!_config.ExecutionLimits.ContainsKey(sdkEvent)) + return -1; + + _config.ExecutionLimits.TryGetValue(sdkEvent, out int limit); + return limit; + } + + private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) + { + ValidSdkEvent validSdkEvent; + validSdkEvent.valid = false; + validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; + foreach (KeyValuePair> kvp in _config.RequireAny) + { + if (kvp.Value.Contains(sdkInternalEvent)) + { + validSdkEvent.valid = true; + validSdkEvent.sdkEvent = kvp.Key; + return validSdkEvent; + } + } + + return validSdkEvent; } #endregion } diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs new file mode 100644 index 00000000..740873c9 --- /dev/null +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -0,0 +1,10 @@ +using Splitio.Domain; +using System; + +namespace Splitio.Services.Common +{ + public interface IEventDelivery + { + void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata, EventHandler handler); + } +} diff --git a/src/Splitio/Services/Common/IEventHandler.cs b/src/Splitio/Services/Common/IEventHandler.cs deleted file mode 100644 index 91bbdbd2..00000000 --- a/src/Splitio/Services/Common/IEventHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ - -namespace Splitio.Services.Common -{ - public interface IEventHandler - { - void SubscribeInternalEvents(); - void ClearInternalEventsSubscription(); - } -} diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index 7a0000d9..ceb41817 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,10 +1,12 @@ using Splitio.Domain; +using System; namespace Splitio.Services.Common { public interface IEventsManager { - void OnSdkInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); - void OnSdkEvent(SdkEvent sdkEvent, EventMetadata eventMetadata); + void NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); + void Register(SdkEvent sdkEvent, EventHandler handler); + void Unregister(SdkEvent sdkEvent); } } diff --git a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs b/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs deleted file mode 100644 index 42dbbf31..00000000 --- a/tests/Splitio-tests/Integration Tests/SdkEventsTest.cs +++ /dev/null @@ -1,76 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Splitio.Domain; -using Splitio.Services.Common; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using EventHandler = Splitio.Services.Common.EventHandler; - -namespace Splitio_Tests.Integration_Tests -{ - [TestClass] - public class SdkEventsTest - { - private bool _sdkUpdate = false; - private bool _sdkReady = false; - private EventMetadata _eventMetadata; - - [TestMethod] - public void TriggerAndCatchEventsTest() - { - //Arrange - EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); - EventsManager eventsManager = new EventsManager(); - EventHandler eventHandler = new EventHandler(config, eventsManager); - eventHandler.SubscribeInternalEvents(); - - eventsManager.PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.PublicSdkReadyHandler += sdkReady_callback; - - Dictionary metaData = new Dictionary - { - { "flags", new List {{ "flag1" }} } - }; - Dictionary metaData2 = new Dictionary(); - - eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData2)); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData2)); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Assert.IsFalse(_sdkUpdate); - Assert.IsFalse(_sdkReady); - - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData2)); - System.Threading.SpinWait.SpinUntil(() => _sdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(_sdkReady); - Assert.IsFalse(_sdkUpdate); - - _sdkReady = false; - _sdkUpdate = false; - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => _sdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(_sdkUpdate); - Assert.IsFalse(_sdkReady); - - _sdkUpdate = false; - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => _sdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(_sdkUpdate); - Assert.IsFalse(_sdkReady); - } - - private void sdkUpdate_callback(object sender, EventMetadata metadata) - { - _sdkUpdate = true; - _eventMetadata = metadata; - } - - private void sdkReady_callback(object sender, EventMetadata metadata) - { - _sdkReady = true; - _eventMetadata = metadata; - } - } -} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs new file mode 100644 index 00000000..b35b774e --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -0,0 +1,49 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Splitio.Domain; +using Splitio.Services.Common; +using System; +using System.Collections.Generic; + +namespace Splitio_Tests.Unit_Tests.Common +{ + [TestClass] + public class EventDeliveryTests + { + private bool SdkReady = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkReadyHandler; + + [TestMethod] + public void TestFiringEvents() + { + //Act + EventDelivery eventDelivery = new EventDelivery(); + + PublicSdkReadyHandler += sdkReady_callback; + + Dictionary metaData = new Dictionary + { + { "flags", new List {{ "flag1" }} } + }; + + eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), PublicSdkReadyHandler); + + Assert.IsTrue(SdkReady); + VerifyMetadata(eMetadata); + } + + void VerifyMetadata(EventMetadata eMetdata) + { + Assert.IsTrue(eMetadata.ContainKey("flags")); + List flags = (List)eMetadata.GetData()["flags"]; + Assert.IsTrue(flags.Count == 1); + Assert.IsTrue(flags.Contains("flag1")); + } + + private void sdkReady_callback(object sender, EventMetadata metadata) + { + SdkReady = true; + eMetadata = metadata; + } + } +} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs b/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs deleted file mode 100644 index 12a6dde9..00000000 --- a/tests/Splitio-tests/Unit Tests/Common/EventHandlerTest.cs +++ /dev/null @@ -1,153 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Splitio.Domain; -using Splitio.Services.Common; -using System; -using System.Collections.Generic; -using System.Threading; -using EventHandler = Splitio.Services.Common.EventHandler; - -namespace Splitio_Tests.Unit_Tests.Common -{ - [TestClass] - public class EventHandlerTest - { - private bool SdkReady = false; - private bool SdkTimedOut = false; - private bool SdkUpdate = false; - private EventMetadata eMetadata = null; - - [TestMethod] - public void TriggerAndCatchEventsTest() - { - //Arrange - EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); - EventsManager eventsManager = new EventsManager(); - - EventHandler eventHandler = new EventHandler(config, eventsManager); - eventHandler.SubscribeInternalEvents(); - - eventsManager.PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.PublicSdkReadyHandler += sdkReady_callback; - eventsManager.PublicSdkTimedOutHandler += sdkTimedOut_callback; - - Dictionary metaData = new Dictionary - { - { "flags", new List {{ "flag1" }} } - }; - EventMetadata eventMetadata = new EventMetadata(metaData); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, eventMetadata); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, eventMetadata); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, eventMetadata); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkTimedOut); - - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); - VerifyMetadata(eMetadata); - - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkUpdate); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkTimedOut); - VerifyMetadata(eMetadata); - - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkUpdate); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkTimedOut); - VerifyMetadata(eMetadata); - - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkUpdate); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkTimedOut); - VerifyMetadata(eMetadata); - - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkUpdate); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkTimedOut); - VerifyMetadata(eMetadata); - - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkTimedOut); - VerifyMetadata(eMetadata); - } - - [TestMethod] - public void SubscribeInternalEventsTest() - { - //Arrange - EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); - EventsManager eventsManager = new EventsManager(); - - EventHandler eventHandler = new EventHandler(config, eventsManager); - eventsManager.PublicSdkTimedOutHandler += sdkTimedOut_callback; - EventMetadata eventMetadata = new EventMetadata(new Dictionary()); - - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, eventMetadata); - Assert.IsFalse(SdkTimedOut); - - SdkTimedOut = false; - eventHandler.SubscribeInternalEvents(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, eventMetadata); - Assert.IsTrue(SdkTimedOut); - - SdkTimedOut = false; - eventHandler.ClearInternalEventsSubscription(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, eventMetadata); - Assert.IsFalse(SdkTimedOut); - } - - void ResetAllVariables() - { - SdkReady = false; - SdkTimedOut = false; - eMetadata = null; - SdkUpdate = false; - } - - void VerifyMetadata(EventMetadata eMetdata) - { - Assert.IsTrue(eMetadata.ContainKey("flags")); - List flags = (List)eMetadata.GetData()["flags"]; - Assert.IsTrue(flags.Count == 1); - Assert.IsTrue(flags.Contains("flag1")); - } - - private void sdkUpdate_callback(object sender, EventMetadata metadata) - { - SdkUpdate = true; - eMetadata = metadata; - } - - private void sdkReady_callback(object sender, EventMetadata metadata) - { - SdkReady = true; - eMetadata = metadata; - } - - private void sdkTimedOut_callback(object sender, EventMetadata metadata) - { - SdkTimedOut = true; - eMetadata = metadata; - } - } -} diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index 18693c79..abf42ac6 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -19,7 +19,7 @@ public void BuildInstance() Assert.IsTrue(require1.Contains(SdkInternalEvent.SdkReady)); config.Prerequisites.TryGetValue(SdkEvent.SdkUpdate, out var ready2); - Assert.IsTrue(ready2.Contains(SdkInternalEvent.SdkReady)); + Assert.IsTrue(ready2.Contains(SdkEvent.SdkReady)); config.ExecutionLimits.TryGetValue(SdkEvent.SdkReadyTimeout, out var timout); Assert.AreEqual(1, timout); diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index fc631f32..c3628ce8 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -3,149 +3,111 @@ using Splitio.Services.Common; using System; using System.Collections.Generic; -using System.Threading; namespace Splitio_Tests.Unit_Tests.Common { [TestClass] public class EventsManagerTests { - private bool RuleBasedSegmentsUpdated = false; - private bool FlagsUpdated = false; - private bool FlagKilledNotification = false; - private bool SegmentsUpdated = false; private bool SdkReady = false; private bool SdkTimedOut = false; private bool SdkUpdate = false; private EventMetadata eMetadata = null; + public event EventHandler PublicSdkReadyHandler; + public event EventHandler PublicSdkUpdateHandler; + public event EventHandler PublicSdkTimedOutHandler; [TestMethod] - public void TestFiringInternalEvents() + public void TestFiringEvents() { //Act EventsManager eventsManager = new EventsManager(); - eventsManager.RuleBasedSegmentsUpdatedHandler += EventManager_RuleBasedSegmentsUpdatedHandler; - eventsManager.FlagKilledNotificationHandler += EventManager_FlagKilledNotificationHandler; - eventsManager.FlagsUpdatedHandler += EventManager_FlagsUpdatedHandler; - eventsManager.SegmentsUpdatedHandler += EventManager_SegmentsUpdatedHandler; - eventsManager.SdkReadyHandler += EventManager_SdkReadyHandler; - eventsManager.SdkTimedOutHandler += EventManager_SdkTimedOutHandler; - eventsManager.PublicSdkReadyHandler += sdkReady_callback; - eventsManager.PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.PublicSdkTimedOutHandler += sdkTimedOut_callback; + PublicSdkReadyHandler += sdkReady_callback; + PublicSdkUpdateHandler += sdkUpdate_callback; + PublicSdkTimedOutHandler += sdkTimedOut_callback; Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventsManager.OnSdkInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => RuleBasedSegmentsUpdated, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(RuleBasedSegmentsUpdated); - VerifyMetadata(eMetadata); + eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => FlagKilledNotification, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(FlagKilledNotification); - VerifyMetadata(eMetadata); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkTimedOut); - ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkTimedOut); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet + + eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkUpdate); Assert.IsTrue(SdkTimedOut); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => FlagsUpdated, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(FlagsUpdated); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReady); + Assert.IsTrue(SdkUpdate); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.OnSdkInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SegmentsUpdated, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SegmentsUpdated); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReady); + Assert.IsTrue(SdkUpdate); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.OnSdkEvent(SdkEvent.SdkReady, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkReady); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReady); + Assert.IsTrue(SdkUpdate); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.OnSdkEvent(SdkEvent.SdkUpdate, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReady); Assert.IsTrue(SdkUpdate); VerifyMetadata(eMetadata); + eventsManager.Unregister(SdkEvent.SdkUpdate); ResetAllVariables(); - eventsManager.OnSdkEvent(SdkEvent.SdkReadyTimeout, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkTimedOut); - VerifyMetadata(eMetadata); - } - - - [TestMethod] - public void TestEventsStatus() - { - EventsManager eventsManager = new EventsManager(); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification)); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated)); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated)); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut)); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated)); - Assert.IsFalse(eventsManager.GetSdkEventStatus(SdkEvent.SdkReady)); - Assert.IsFalse(eventsManager.GetSdkEventStatus(SdkEvent.SdkUpdate)); - Assert.IsFalse(eventsManager.GetSdkEventStatus(SdkEvent.SdkReadyTimeout)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, true); - Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, true); - Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, true); - Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, true); - Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, true); - Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, true); - Assert.IsTrue(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut)); - - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, false); - Assert.IsFalse(eventsManager.GetSdkInternalEventStatus(SdkInternalEvent.SdkReady)); - - eventsManager.UpdateSdkEventStatus(SdkEvent.SdkReady, true); - Assert.IsTrue(eventsManager.GetSdkEventStatus(SdkEvent.SdkReady)); - - eventsManager.UpdateSdkEventStatus(SdkEvent.SdkUpdate, true); - Assert.IsTrue(eventsManager.GetSdkEventStatus(SdkEvent.SdkUpdate)); - - eventsManager.UpdateSdkEventStatus(SdkEvent.SdkReadyTimeout, true); - Assert.IsTrue(eventsManager.GetSdkEventStatus(SdkEvent.SdkReadyTimeout)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkUpdate); } void ResetAllVariables() { - RuleBasedSegmentsUpdated = false; - FlagsUpdated = false; - FlagKilledNotification = false; - SegmentsUpdated = false; SdkReady = false; SdkTimedOut = false; eMetadata = null; @@ -160,42 +122,6 @@ void VerifyMetadata(EventMetadata eMetdata) Assert.IsTrue(flags.Contains("flag1")); } - void EventManager_RuleBasedSegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) - { - RuleBasedSegmentsUpdated = true; - eMetadata = eventMetadata; - } - - void EventManager_FlagsUpdatedHandler(object sender, EventMetadata eventMetadata) - { - FlagsUpdated = true; - eMetadata = eventMetadata; - } - - void EventManager_FlagKilledNotificationHandler(object sender, EventMetadata eventMetadata) - { - FlagKilledNotification = true; - eMetadata = eventMetadata; - } - - void EventManager_SegmentsUpdatedHandler(object sender, EventMetadata eventMetadata) - { - SegmentsUpdated = true; - eMetadata = eventMetadata; - } - - void EventManager_SdkReadyHandler(object sender, EventMetadata eventMetadata) - { - SdkReady = true; - eMetadata = eventMetadata; - } - - void EventManager_SdkTimedOutHandler(object sender, EventMetadata eventMetadata) - { - SdkTimedOut = true; - eMetadata = eventMetadata; - } - private void sdkUpdate_callback(object sender, EventMetadata metadata) { SdkUpdate = true; From 83d98c1b41cda49aa906d51e72c1342e9be33e43 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 11 Dec 2025 15:25:13 -0800 Subject: [PATCH 21/87] polishing --- src/Splitio/Services/Common/EventsManager.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 1f921cd6..0ae1651c 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -10,9 +10,9 @@ namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - ConcurrentDictionary> _activeEvents; - string Triggered = "Triggered"; - string EventHandler = "EventHandler"; + private readonly ConcurrentDictionary> _activeEvents; + private readonly string Triggered = "Triggered"; + private readonly string EventHandler = "EventHandler"; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); private readonly EventsManagerConfig _config; @@ -51,12 +51,9 @@ public void Unregister(SdkEvent sdkEvent) { if (_activeEvents.ContainsKey(sdkEvent)) { - if (_activeEvents.TryGetValue(sdkEvent, out var dict)) + if (_activeEvents.TryGetValue(sdkEvent, out var dict) && dict.Count > 0) { - if (dict.Count > 0) - { - _activeEvents.TryRemove(sdkEvent, out _); - } + _activeEvents.TryRemove(sdkEvent, out _); } } } From d3d024027835d22ccf2232bafec1e3615d6bd83e Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 11 Dec 2025 15:35:04 -0800 Subject: [PATCH 22/87] polish --- src/Splitio/Services/Common/EventsManager.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 0ae1651c..15fe47b2 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -49,12 +49,11 @@ public void Register(SdkEvent sdkEvent, EventHandler handler) public void Unregister(SdkEvent sdkEvent) { - if (_activeEvents.ContainsKey(sdkEvent)) + if (_activeEvents.ContainsKey(sdkEvent) + && _activeEvents.TryGetValue(sdkEvent, out var dict) + && dict.Count > 0) { - if (_activeEvents.TryGetValue(sdkEvent, out var dict) && dict.Count > 0) - { - _activeEvents.TryRemove(sdkEvent, out _); - } + _activeEvents.TryRemove(sdkEvent, out _); } } From f054f1399ee70be807d6e9267a45d61933a70186 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 12 Dec 2025 10:04:21 -0800 Subject: [PATCH 23/87] fixed suppressed by condition --- src/Splitio/Domain/EventsManagerConfig.cs | 12 ++--- src/Splitio/Services/Common/EventsManager.cs | 51 ++++++++++++++----- .../Common/EventsManagerConfigTests.cs | 6 ++- .../Unit Tests/Common/EventsManagerTests.cs | 23 ++++++--- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 86de75cb..2d5b56de 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -7,14 +7,14 @@ public class EventsManagerConfig public Dictionary> RequireAll { get; private set; } public Dictionary> RequireAny { get; private set; } public Dictionary> Prerequisites { get; private set; } - public Dictionary> SuppressedBy { get; private set; } + public Dictionary> SuppressedBy { get; private set; } public Dictionary ExecutionLimits { get; private set; } private EventsManagerConfig( Dictionary> requireAll, Dictionary> requireAny, Dictionary> prerequisites, - Dictionary> suppressedBy, + Dictionary> suppressedBy, Dictionary executionLimits) { RequireAll = requireAll; @@ -63,17 +63,17 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; - Dictionary> suppressedBy = new Dictionary> + Dictionary> suppressedBy = new Dictionary> { - { SdkEvent.SdkReadyTimeout, new HashSet - { SdkInternalEvent.SdkReady } + { SdkEvent.SdkReadyTimeout, new HashSet + { SdkEvent.SdkReady } } }; Dictionary executionLimits = new Dictionary { - { SdkEvent.SdkReadyTimeout, 1 }, + { SdkEvent.SdkReadyTimeout, -1 }, { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 15fe47b2..8f6698ce 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -10,7 +10,7 @@ namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - private readonly ConcurrentDictionary> _activeEvents; + private readonly ConcurrentDictionary> _activeSubscriptions; private readonly string Triggered = "Triggered"; private readonly string EventHandler = "EventHandler"; private readonly ConcurrentDictionary _internalEventsStatus; @@ -26,7 +26,7 @@ struct ValidSdkEvent public EventsManager() { - _activeEvents = new ConcurrentDictionary>(); + _activeSubscriptions = new ConcurrentDictionary>(); _internalEventsStatus = BuildInternalSdkEventStatus(); _config = EventsManagerConfig.BuildEventsManagerConfig(); _eventDelivery = new EventDelivery(); @@ -35,10 +35,10 @@ public EventsManager() #region Public Methods public void Register(SdkEvent sdkEvent, EventHandler handler) { - _activeEvents.TryGetValue(sdkEvent, out var dict); + _activeSubscriptions.TryGetValue(sdkEvent, out var dict); if (dict == null) { - _activeEvents.TryAdd(sdkEvent, new Dictionary() + _activeSubscriptions.TryAdd(sdkEvent, new Dictionary() { {Triggered, false}, {EventHandler, handler} @@ -49,11 +49,11 @@ public void Register(SdkEvent sdkEvent, EventHandler handler) public void Unregister(SdkEvent sdkEvent) { - if (_activeEvents.ContainsKey(sdkEvent) - && _activeEvents.TryGetValue(sdkEvent, out var dict) + if (_activeSubscriptions.ContainsKey(sdkEvent) + && _activeSubscriptions.TryGetValue(sdkEvent, out var dict) && dict.Count > 0) - { - _activeEvents.TryRemove(sdkEvent, out _); + { + _activeSubscriptions.TryRemove(sdkEvent, out _); } } @@ -84,7 +84,7 @@ public void NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata #region Private Methods private void SetSdkEventTriggered(SdkEvent sdkEvent) { - if (!_activeEvents.TryGetValue(sdkEvent, out var dict)) + if (!_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) { return; } @@ -96,12 +96,12 @@ private void SetSdkEventTriggered(SdkEvent sdkEvent) Dictionary dict2 = new Dictionary(dict); dict2[Triggered] = true; - _activeEvents.TryUpdate(sdkEvent, dict2, dict); + _activeSubscriptions.TryUpdate(sdkEvent, dict2, dict); } private bool EventAlreadyTriggered(SdkEvent sdkEvent) { - if (_activeEvents.TryGetValue(sdkEvent, out Dictionary triggered)) + if (_activeSubscriptions.TryGetValue(sdkEvent, out Dictionary triggered)) { triggered.TryGetValue(Triggered, out var trig); return (bool)trig; @@ -111,7 +111,7 @@ private bool EventAlreadyTriggered(SdkEvent sdkEvent) private EventHandler GetEventHandler(SdkEvent sdkEvent) { - if (_activeEvents.TryGetValue(sdkEvent, out var dict)) + if (_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) { dict.TryGetValue(EventHandler, out var handler); return (EventHandler)handler; @@ -157,14 +157,19 @@ private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) return requireAnySdkEvent; } - if (requireAnySdkEvent.valid && !EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) - && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) + if (requireAnySdkEvent.valid && ((!EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) + && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) || ExecutionLimit(requireAnySdkEvent.sdkEvent) == -1)) { _logger.Debug($"EventHandler: Detected Event {requireAnySdkEvent.sdkEvent} is available for internal event {sdkInternalEvent}"); finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; } finalSdkEvent.valid = CheckPrerequisites(finalSdkEvent.sdkEvent); + if (finalSdkEvent.valid) + { + finalSdkEvent.valid = CheckSuppressedBy(finalSdkEvent.sdkEvent); + } + if (finalSdkEvent.valid) { _logger.Debug($"EventHandler: Event {requireAnySdkEvent.sdkEvent} is eligable for notification."); @@ -214,6 +219,24 @@ private bool CheckPrerequisites(SdkEvent sdkEvent) return true; } + private bool CheckSuppressedBy(SdkEvent sdkEvent) + { + foreach (KeyValuePair> kvp in _config.SuppressedBy) + { + if (kvp.Key == sdkEvent) + { + if (kvp.Value.Any(x => EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + private int ExecutionLimit(SdkEvent sdkEvent) { if (!_config.ExecutionLimits.ContainsKey(sdkEvent)) diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index abf42ac6..ef765289 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -22,7 +22,7 @@ public void BuildInstance() Assert.IsTrue(ready2.Contains(SdkEvent.SdkReady)); config.ExecutionLimits.TryGetValue(SdkEvent.SdkReadyTimeout, out var timout); - Assert.AreEqual(1, timout); + Assert.AreEqual(-1, timout); config.ExecutionLimits.TryGetValue(SdkEvent.SdkUpdate, out var update); Assert.AreEqual(-1, update); config.ExecutionLimits.TryGetValue(SdkEvent.SdkReady, out var ready); @@ -37,6 +37,10 @@ public void BuildInstance() Assert.IsTrue(require2.Contains(SdkInternalEvent.RuleBasedSegmentsUpdated)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagKilledNotification)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagsUpdated)); + + config.SuppressedBy.TryGetValue(SdkEvent.SdkReadyTimeout, out var require4); + Assert.AreEqual(1, require3.Count); + Assert.IsTrue(require4.Contains(SdkEvent.SdkReady)); } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index c3628ce8..078c9df1 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -43,13 +43,6 @@ public void TestFiringEvents() Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); - VerifyMetadata(eMetadata); - ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); @@ -65,6 +58,22 @@ public void TestFiringEvents() Assert.IsTrue(SdkTimedOut); VerifyMetadata(eMetadata); + ResetAllVariables(); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); + Assert.IsTrue(SdkReady); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkTimedOut); + VerifyMetadata(eMetadata); + + ResetAllVariables(); + eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReady); + Assert.IsFalse(SdkUpdate); + Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady + ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); From 29b6a04b10909421c5378601b1a12d733cc6dd09 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 12 Dec 2025 11:40:20 -0800 Subject: [PATCH 24/87] added generic type events --- src/Splitio/Domain/EventsManagerConfig.cs | 38 ++++++++++++------- src/Splitio/Services/Common/EventsManager.cs | 2 +- src/Splitio/Services/Common/IEventsManager.cs | 8 ++-- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 2d5b56de..960aee05 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -4,6 +4,16 @@ namespace Splitio.Domain { public class EventsManagerConfig { + public struct EventsManagerConfigStruct + { + public Dictionary> RequireAll; + public Dictionary> RequireAny; + public Dictionary> Prerequisites; + public Dictionary> SuppressedBy; + public Dictionary ExecutionLimits; + } + public EventsManagerConfigStruct ConfigManagerStruct { get; private set; } + public Dictionary> RequireAll { get; private set; } public Dictionary> RequireAny { get; private set; } public Dictionary> Prerequisites { get; private set; } @@ -11,17 +21,13 @@ public class EventsManagerConfig public Dictionary ExecutionLimits { get; private set; } private EventsManagerConfig( - Dictionary> requireAll, - Dictionary> requireAny, - Dictionary> prerequisites, - Dictionary> suppressedBy, - Dictionary executionLimits) - { - RequireAll = requireAll; - RequireAny = requireAny; - Prerequisites = prerequisites; - SuppressedBy = suppressedBy; - ExecutionLimits = executionLimits; + EventsManagerConfigStruct configManagerStruct) + { + RequireAll = configManagerStruct.RequireAll; + RequireAny = configManagerStruct.RequireAny; + Prerequisites = configManagerStruct.Prerequisites; + SuppressedBy = configManagerStruct.SuppressedBy; + ExecutionLimits = configManagerStruct.ExecutionLimits; } public static EventsManagerConfig BuildEventsManagerConfig() @@ -77,8 +83,14 @@ public static EventsManagerConfig BuildEventsManagerConfig() { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; - - return new EventsManagerConfig(requireAll, requireAny, prerequisites, suppressedBy, executionLimits); + return new EventsManagerConfig(new EventsManagerConfigStruct + { + Prerequisites = prerequisites, + ExecutionLimits = executionLimits, + SuppressedBy = suppressedBy, + RequireAll = requireAll, + RequireAny = requireAny + }); } } } diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 8f6698ce..e265ad2a 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -8,7 +8,7 @@ namespace Splitio.Services.Common { - public class EventsManager : IEventsManager + public class EventsManager : IEventsManager { private readonly ConcurrentDictionary> _activeSubscriptions; private readonly string Triggered = "Triggered"; diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index ceb41817..b3db9aec 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -3,10 +3,10 @@ namespace Splitio.Services.Common { - public interface IEventsManager + public interface IEventsManager { - void NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); - void Register(SdkEvent sdkEvent, EventHandler handler); - void Unregister(SdkEvent sdkEvent); + void NotifyInternalEvent(I sdkInternalEvent, EventMetadata eventMetadata); + void Register(E sdkEvent, EventHandler handler); + void Unregister(E sdkEvent); } } From e9732e353d5f39b93dcdbbdec3f71273b52ed85d Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 12 Dec 2025 20:55:21 -0800 Subject: [PATCH 25/87] Used abstract events in EventsManager class --- src/Splitio/Domain/EventsManagerConfig.cs | 9 +- src/Splitio/Services/Common/EventDelivery.cs | 4 +- src/Splitio/Services/Common/EventsManager.cs | 209 +++--------------- src/Splitio/Services/Common/IEventDelivery.cs | 4 +- src/Splitio/Services/Common/IEventsManager.cs | 7 +- src/Splitio/Util/Helper.cs | 145 ++++++++++++ .../Unit Tests/Common/EventDeliveryTests.cs | 2 +- .../Unit Tests/Common/EventsManagerTests.cs | 59 +++-- 8 files changed, 236 insertions(+), 203 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 960aee05..0e977e65 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -1,9 +1,13 @@ -using System.Collections.Generic; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; +using System.Collections.Generic; +using System.Linq; namespace Splitio.Domain { public class EventsManagerConfig { + public struct EventsManagerConfigStruct { public Dictionary> RequireAll; @@ -13,13 +17,12 @@ public struct EventsManagerConfigStruct public Dictionary ExecutionLimits; } public EventsManagerConfigStruct ConfigManagerStruct { get; private set; } - public Dictionary> RequireAll { get; private set; } public Dictionary> RequireAny { get; private set; } public Dictionary> Prerequisites { get; private set; } public Dictionary> SuppressedBy { get; private set; } public Dictionary ExecutionLimits { get; private set; } - + private EventsManagerConfig( EventsManagerConfigStruct configManagerStruct) { diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 4c59e21d..c3102af8 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -5,11 +5,11 @@ namespace Splitio.Services.Common { - public class EventDelivery : IEventDelivery + public class EventDelivery : IEventDelivery { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - public virtual void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata, EventHandler handler) + public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler) { if (handler != null) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index e265ad2a..0c3c27d0 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -8,32 +8,25 @@ namespace Splitio.Services.Common { - public class EventsManager : IEventsManager + public class EventsManager : IEventsManager { - private readonly ConcurrentDictionary> _activeSubscriptions; + private readonly ConcurrentDictionary> _activeSubscriptions; private readonly string Triggered = "Triggered"; private readonly string EventHandler = "EventHandler"; - private readonly ConcurrentDictionary _internalEventsStatus; + private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - private readonly EventsManagerConfig _config; - private readonly EventDelivery _eventDelivery; + private readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); - struct ValidSdkEvent - { - public SdkEvent sdkEvent; - public bool valid; - } public EventsManager() { - _activeSubscriptions = new ConcurrentDictionary>(); - _internalEventsStatus = BuildInternalSdkEventStatus(); - _config = EventsManagerConfig.BuildEventsManagerConfig(); - _eventDelivery = new EventDelivery(); + _activeSubscriptions = new ConcurrentDictionary>(); + _internalEventsStatus = new ConcurrentDictionary(); + _eventDelivery = new EventDelivery(); } #region Public Methods - public void Register(SdkEvent sdkEvent, EventHandler handler) + public void Register(E sdkEvent, EventHandler handler) { _activeSubscriptions.TryGetValue(sdkEvent, out var dict); if (dict == null) @@ -47,7 +40,7 @@ public void Register(SdkEvent sdkEvent, EventHandler handler) } } - public void Unregister(SdkEvent sdkEvent) + public void Unregister(E sdkEvent) { if (_activeSubscriptions.ContainsKey(sdkEvent) && _activeSubscriptions.TryGetValue(sdkEvent, out var dict) @@ -57,21 +50,13 @@ public void Unregister(SdkEvent sdkEvent) } } - public void NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) + public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eventsToNotify) { lock (_lock) { _logger.Debug($"EventHandler: Handling internal event {sdkInternalEvent}"); - UpdateSdkInternalEventStatus(sdkInternalEvent, true); - ValidSdkEvent eventToNotify = GetSdkEventIfApplicable(sdkInternalEvent); - if (eventToNotify.valid) - { - _logger.Debug($"EventHandler: Firing Sdk event {eventToNotify.sdkEvent}"); - _eventDelivery.Deliver(eventToNotify.sdkEvent, eventMetadata, GetEventHandler(eventToNotify.sdkEvent)); - SetSdkEventTriggered(eventToNotify.sdkEvent); - } - foreach (SdkEvent sdkEvent in CheckRequireAll()) + foreach (E sdkEvent in eventsToNotify) { _logger.Debug($"EventHandler: Firing Sdk event {sdkEvent}"); _eventDelivery.Deliver(sdkEvent, eventMetadata, GetEventHandler(sdkEvent)); @@ -79,27 +64,8 @@ public void NotifyInternalEvent(SdkInternalEvent sdkInternalEvent, EventMetadata } } } - #endregion - #region Private Methods - private void SetSdkEventTriggered(SdkEvent sdkEvent) - { - if (!_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) - { - return; - } - - if ((bool)dict[Triggered]) - { - return; - } - - Dictionary dict2 = new Dictionary(dict); - dict2[Triggered] = true; - _activeSubscriptions.TryUpdate(sdkEvent, dict2, dict); - } - - private bool EventAlreadyTriggered(SdkEvent sdkEvent) + public bool EventAlreadyTriggered(E sdkEvent) { if (_activeSubscriptions.TryGetValue(sdkEvent, out Dictionary triggered)) { @@ -109,159 +75,46 @@ private bool EventAlreadyTriggered(SdkEvent sdkEvent) return false; } - private EventHandler GetEventHandler(SdkEvent sdkEvent) + public bool GetSdkInternalEventStatus(I sdkInternalEvent) { - if (_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) - { - dict.TryGetValue(EventHandler, out var handler); - return (EventHandler)handler; - } - return null; + _internalEventsStatus.TryGetValue(sdkInternalEvent, out var status); + return status; } - private void UpdateSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent, bool status) + public void UpdateSdkInternalEventStatus(I sdkInternalEvent, bool status) { _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, (_, oldValue) => status); _logger.Debug($"EventManager: Internal Event {sdkInternalEvent} status is updated to {status}"); } + #endregion - private bool GetSdkInternalEventStatus(SdkInternalEvent sdkInternalEvent) - { - _internalEventsStatus.TryGetValue(sdkInternalEvent, out var status); - return status; - } - - private static ConcurrentDictionary BuildInternalSdkEventStatus() - { - ConcurrentDictionary statuses = new ConcurrentDictionary(); - statuses.TryAdd(SdkInternalEvent.SdkReady, false); - statuses.TryAdd(SdkInternalEvent.RuleBasedSegmentsUpdated, false); - statuses.TryAdd(SdkInternalEvent.SdkTimedOut, false); - statuses.TryAdd(SdkInternalEvent.SegmentsUpdated, false); - statuses.TryAdd(SdkInternalEvent.FlagKilledNotification, false); - statuses.TryAdd(SdkInternalEvent.FlagsUpdated, false); - return statuses; - } - - private ValidSdkEvent GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent) - { - ValidSdkEvent finalSdkEvent; - finalSdkEvent.valid = false; - finalSdkEvent.sdkEvent = SdkEvent.SdkUpdate; - - ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); - if (!requireAnySdkEvent.valid) - { - _logger.Debug($"EventHandler: No Event available for internal event {sdkInternalEvent}"); - return requireAnySdkEvent; - } - - if (requireAnySdkEvent.valid && ((!EventAlreadyTriggered(requireAnySdkEvent.sdkEvent) - && ExecutionLimit(requireAnySdkEvent.sdkEvent) == 1) || ExecutionLimit(requireAnySdkEvent.sdkEvent) == -1)) - { - _logger.Debug($"EventHandler: Detected Event {requireAnySdkEvent.sdkEvent} is available for internal event {sdkInternalEvent}"); - finalSdkEvent.sdkEvent = requireAnySdkEvent.sdkEvent; - } - - finalSdkEvent.valid = CheckPrerequisites(finalSdkEvent.sdkEvent); - if (finalSdkEvent.valid) - { - finalSdkEvent.valid = CheckSuppressedBy(finalSdkEvent.sdkEvent); - } - - if (finalSdkEvent.valid) - { - _logger.Debug($"EventHandler: Event {requireAnySdkEvent.sdkEvent} is eligable for notification."); - } - return finalSdkEvent; - } - - private List CheckRequireAll() - { - List events = new List(); - foreach (KeyValuePair> kvp in _config.RequireAll) - { - bool finalStatus = true; - foreach (var val in kvp.Value) - { - finalStatus &= GetSdkInternalEventStatus(val); - } - if (finalStatus - && CheckPrerequisites(kvp.Key) - && ((ExecutionLimit(kvp.Key) == 1 && !EventAlreadyTriggered(kvp.Key)) - || (ExecutionLimit(kvp.Key) == -1)) - && kvp.Value.Count > 0) - { - _logger.Debug($"EventHandler: Event {kvp.Key} is eligable as require all for notification."); - events.Add(kvp.Key); - } - } - - return events; - } - - private bool CheckPrerequisites(SdkEvent sdkEvent) + #region Private Methods + private void SetSdkEventTriggered(E sdkEvent) { - foreach (KeyValuePair> kvp in _config.Prerequisites) + if (!_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return; } - return true; - } - - private bool CheckSuppressedBy(SdkEvent sdkEvent) - { - foreach (KeyValuePair> kvp in _config.SuppressedBy) + if ((bool)dict[Triggered]) { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return; } - return true; - } - - private int ExecutionLimit(SdkEvent sdkEvent) - { - if (!_config.ExecutionLimits.ContainsKey(sdkEvent)) - return -1; - - _config.ExecutionLimits.TryGetValue(sdkEvent, out int limit); - return limit; + Dictionary dict2 = new Dictionary(dict); + dict2[Triggered] = true; + _activeSubscriptions.TryUpdate(sdkEvent, dict2, dict); } - private ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent) + private EventHandler GetEventHandler(E sdkEvent) { - ValidSdkEvent validSdkEvent; - validSdkEvent.valid = false; - validSdkEvent.sdkEvent = SdkEvent.SdkUpdate; - foreach (KeyValuePair> kvp in _config.RequireAny) + if (_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.valid = true; - validSdkEvent.sdkEvent = kvp.Key; - return validSdkEvent; - } + dict.TryGetValue(EventHandler, out var handler); + return (EventHandler)handler; } - - return validSdkEvent; + return null; } #endregion } diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs index 740873c9..550cfbbf 100644 --- a/src/Splitio/Services/Common/IEventDelivery.cs +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -3,8 +3,8 @@ namespace Splitio.Services.Common { - public interface IEventDelivery + public interface IEventDelivery { - void Deliver(SdkEvent sdkEvent, EventMetadata eventMetadata, EventHandler handler); + void Deliver(E sdkEvent, M eventMetadata, EventHandler handler); } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index b3db9aec..fd606b1a 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,12 +1,13 @@ using Splitio.Domain; using System; +using System.Collections.Generic; namespace Splitio.Services.Common { - public interface IEventsManager + public interface IEventsManager { - void NotifyInternalEvent(I sdkInternalEvent, EventMetadata eventMetadata); - void Register(E sdkEvent, EventHandler handler); + void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eventsToNotify); + void Register(E sdkEvent, EventHandler handler); void Unregister(E sdkEvent); } } diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index 84dc8dda..8b27ff44 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -1,9 +1,11 @@ using Splitio.CommonLibraries; using Splitio.Domain; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Logger; using Splitio.Telemetry.Domain.Enums; using Splitio.Telemetry.Storages; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -11,6 +13,12 @@ namespace Splitio.Util { public class Helper { + public struct ValidSdkEvent + { + public SdkEvent SdkEvent; + public bool Valid; + } + public static List TakeFromList(List items, int size) { if (items == null) return new List(); @@ -84,5 +92,142 @@ public static string getFallbackConfig(FallbackTreatment fallbackTreatment) return null; } + + public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent, + EventsManagerConfig eventsManagerConfig, + EventsManager eventsManager) + { + ValidSdkEvent finalSdkEvent = new ValidSdkEvent + { + Valid = false, + SdkEvent = SdkEvent.SdkReady + }; + eventsManager.UpdateSdkInternalEventStatus(sdkInternalEvent, true); + List eventsToFire = new List(); + + ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent, eventsManagerConfig); + if (requireAnySdkEvent.Valid) + { + if ((!eventsManager.EventAlreadyTriggered(requireAnySdkEvent.SdkEvent) + && ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManagerConfig) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManagerConfig) == -1) + { + finalSdkEvent.SdkEvent = requireAnySdkEvent.SdkEvent; + } + + finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent, eventsManagerConfig, eventsManager) + && CheckSuppressedBy(finalSdkEvent.SdkEvent, eventsManagerConfig, eventsManager); + } + + if (finalSdkEvent.Valid) + { + eventsToFire.Add(finalSdkEvent.SdkEvent); + } + + foreach (SdkEvent sdkEvent in CheckRequireAll(eventsManagerConfig, eventsManager)) + { + eventsToFire.Add(sdkEvent); + } + + return eventsToFire; + } + + private static List CheckRequireAll(EventsManagerConfig eventsManagerConfig, + EventsManager eventsManager) + { + List events = new List(); + foreach (KeyValuePair> kvp in eventsManagerConfig.RequireAll) + { + bool finalStatus = true; + foreach (var val in kvp.Value) + { + finalStatus &= eventsManager.GetSdkInternalEventStatus(val); + } + if (finalStatus + && CheckPrerequisites(kvp.Key, eventsManagerConfig, eventsManager) + && ((ExecutionLimit(kvp.Key, eventsManagerConfig) == 1 && !eventsManager.EventAlreadyTriggered(kvp.Key)) + || (ExecutionLimit(kvp.Key, eventsManagerConfig) == -1)) + && kvp.Value.Count > 0) + { + events.Add(kvp.Key); + } + } + + return events; + } + + private static bool CheckPrerequisites(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig, + EventsManager eventsManager) + { + foreach (KeyValuePair> kvp in eventsManagerConfig.Prerequisites) + { + if (kvp.Key == sdkEvent) + { + if (kvp.Value.Any(x => !eventsManager.EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + + private static bool CheckSuppressedBy(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig, + EventsManager eventsManager) + { + foreach (KeyValuePair> kvp in eventsManagerConfig.SuppressedBy) + { + if (kvp.Key == sdkEvent) + { + if (kvp.Value.Any(x => eventsManager.EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + + private static int ExecutionLimit(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig) + { + if (!eventsManagerConfig.ExecutionLimits.ContainsKey(sdkEvent)) + return -1; + + eventsManagerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); + return limit; + } + + private static ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent, EventsManagerConfig eventsManagerConfig) + { + ValidSdkEvent validSdkEvent; + validSdkEvent.Valid = false; + validSdkEvent.SdkEvent = SdkEvent.SdkUpdate; + foreach (KeyValuePair> kvp in eventsManagerConfig.RequireAny) + { + if (kvp.Value.Contains(sdkInternalEvent)) + { + validSdkEvent.Valid = true; + validSdkEvent.SdkEvent = kvp.Key; + return validSdkEvent; + } + } + + return validSdkEvent; + } + + public static void BuildInternalSdkEventStatus(EventsManager eventsManager) + { + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, false); + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, false); + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, false); + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, false); + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, false); + eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, false); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index b35b774e..80711087 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -17,7 +17,7 @@ public class EventDeliveryTests public void TestFiringEvents() { //Act - EventDelivery eventDelivery = new EventDelivery(); + EventDelivery eventDelivery = new EventDelivery(); PublicSdkReadyHandler += sdkReady_callback; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 078c9df1..bc4bef7a 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -1,8 +1,10 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; +using Splitio.Redis.Services.Shared; using Splitio.Services.Common; using System; using System.Collections.Generic; +using Splitio.Util; namespace Splitio_Tests.Unit_Tests.Common { @@ -21,7 +23,9 @@ public class EventsManagerTests public void TestFiringEvents() { //Act - EventsManager eventsManager = new EventsManager(); + EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + EventsManager eventsManager = new EventsManager(); + Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); PublicSdkReadyHandler += sdkReady_callback; PublicSdkUpdateHandler += sdkUpdate_callback; @@ -35,23 +39,35 @@ public void TestFiringEvents() eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, + config, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, + config, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, + config, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, + config, eventsManager)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); @@ -59,7 +75,10 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); + List eventsToNotify = Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, + config, eventsManager); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData), + eventsToNotify); System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); Assert.IsFalse(SdkUpdate); @@ -68,14 +87,18 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -83,7 +106,9 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -91,7 +116,9 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -99,7 +126,9 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -108,7 +137,9 @@ public void TestFiringEvents() eventsManager.Unregister(SdkEvent.SdkUpdate); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, + config, eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); From 7c4f85e4a3dce26f690ba9d52d41049170e66bea Mon Sep 17 00:00:00 2001 From: Bill Al Date: Sat, 13 Dec 2025 13:18:28 -0800 Subject: [PATCH 26/87] polish --- src/Splitio/Domain/EventsManagerConfig.cs | 17 +++++++---------- src/Splitio/Services/Common/EventsManager.cs | 4 +--- src/Splitio/Util/Helper.cs | 4 ++-- 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 0e977e65..c4bebdc8 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -1,7 +1,4 @@ -using Splitio.Services.Logger; -using Splitio.Services.Shared.Classes; -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; namespace Splitio.Domain { @@ -10,13 +7,13 @@ public class EventsManagerConfig public struct EventsManagerConfigStruct { - public Dictionary> RequireAll; - public Dictionary> RequireAny; - public Dictionary> Prerequisites; - public Dictionary> SuppressedBy; - public Dictionary ExecutionLimits; + public Dictionary> RequireAll { get; set; } + public Dictionary> RequireAny { get; set; } + public Dictionary> Prerequisites { get; set; } + public Dictionary> SuppressedBy { get; set; } + public Dictionary ExecutionLimits { get; set; } } - public EventsManagerConfigStruct ConfigManagerStruct { get; private set; } + public EventsManagerConfigStruct ConfigManagerStruct { get; set; } public Dictionary> RequireAll { get; private set; } public Dictionary> RequireAny { get; private set; } public Dictionary> Prerequisites { get; private set; } diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 0c3c27d0..8f31e079 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -1,10 +1,8 @@ -using Splitio.Domain; -using Splitio.Services.Logger; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; namespace Splitio.Services.Common { diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index 8b27ff44..8b2d3be4 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -15,8 +15,8 @@ public class Helper { public struct ValidSdkEvent { - public SdkEvent SdkEvent; - public bool Valid; + public SdkEvent SdkEvent { get; set; } + public bool Valid { get; set; } } public static List TakeFromList(List items, int size) From 4948606c59becd2e792e83fb39c960df70e1c975 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Sat, 13 Dec 2025 13:25:24 -0800 Subject: [PATCH 27/87] fixed build error --- src/Splitio/Util/Helper.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index 8b2d3be4..4abce8d9 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -5,7 +5,6 @@ using Splitio.Services.Logger; using Splitio.Telemetry.Domain.Enums; using Splitio.Telemetry.Storages; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -204,9 +203,12 @@ private static int ExecutionLimit(SdkEvent sdkEvent, EventsManagerConfig eventsM private static ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent, EventsManagerConfig eventsManagerConfig) { - ValidSdkEvent validSdkEvent; - validSdkEvent.Valid = false; - validSdkEvent.SdkEvent = SdkEvent.SdkUpdate; + ValidSdkEvent validSdkEvent = new ValidSdkEvent + { + Valid = false, + SdkEvent = SdkEvent.SdkUpdate + }; + foreach (KeyValuePair> kvp in eventsManagerConfig.RequireAny) { if (kvp.Value.Contains(sdkInternalEvent)) From ed0a7248d1e0fee7daf2235e2ea8aebefb35dd0f Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 16 Dec 2025 13:43:18 -0800 Subject: [PATCH 28/87] replaced config data struct with class --- src/Splitio/Domain/EventManagerConfigData.cs | 14 ++++++++++++ src/Splitio/Domain/EventsManagerConfig.cs | 24 ++++++-------------- src/Splitio/Services/Common/EventDelivery.cs | 4 ++-- src/Splitio/Services/Common/EventsManager.cs | 16 ++++++------- 4 files changed, 31 insertions(+), 27 deletions(-) create mode 100644 src/Splitio/Domain/EventManagerConfigData.cs diff --git a/src/Splitio/Domain/EventManagerConfigData.cs b/src/Splitio/Domain/EventManagerConfigData.cs new file mode 100644 index 00000000..a85e9ea5 --- /dev/null +++ b/src/Splitio/Domain/EventManagerConfigData.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; + +namespace Splitio.Domain +{ + public class EventManagerConfigData + { + public Dictionary> RequireAll { get; set; } + public Dictionary> RequireAny { get; set; } + public Dictionary> Prerequisites { get; set; } + public Dictionary> SuppressedBy { get; set; } + public Dictionary ExecutionLimits { get; set; } + } +} diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index c4bebdc8..8bf66dae 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -4,16 +4,6 @@ namespace Splitio.Domain { public class EventsManagerConfig { - - public struct EventsManagerConfigStruct - { - public Dictionary> RequireAll { get; set; } - public Dictionary> RequireAny { get; set; } - public Dictionary> Prerequisites { get; set; } - public Dictionary> SuppressedBy { get; set; } - public Dictionary ExecutionLimits { get; set; } - } - public EventsManagerConfigStruct ConfigManagerStruct { get; set; } public Dictionary> RequireAll { get; private set; } public Dictionary> RequireAny { get; private set; } public Dictionary> Prerequisites { get; private set; } @@ -21,13 +11,13 @@ public struct EventsManagerConfigStruct public Dictionary ExecutionLimits { get; private set; } private EventsManagerConfig( - EventsManagerConfigStruct configManagerStruct) + EventManagerConfigData configManagerData) { - RequireAll = configManagerStruct.RequireAll; - RequireAny = configManagerStruct.RequireAny; - Prerequisites = configManagerStruct.Prerequisites; - SuppressedBy = configManagerStruct.SuppressedBy; - ExecutionLimits = configManagerStruct.ExecutionLimits; + RequireAll = configManagerData.RequireAll; + RequireAny = configManagerData.RequireAny; + Prerequisites = configManagerData.Prerequisites; + SuppressedBy = configManagerData.SuppressedBy; + ExecutionLimits = configManagerData.ExecutionLimits; } public static EventsManagerConfig BuildEventsManagerConfig() @@ -83,7 +73,7 @@ public static EventsManagerConfig BuildEventsManagerConfig() { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; - return new EventsManagerConfig(new EventsManagerConfigStruct + return new EventsManagerConfig(new EventManagerConfigData { Prerequisites = prerequisites, ExecutionLimits = executionLimits, diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index c3102af8..34bd2ca6 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -13,14 +13,14 @@ public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler { if (handler != null) { - _logger.Debug($"EventManager: Triggering handle for Sdk Event {sdkEvent}"); + _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { handler(this, eventMetadata); } catch (Exception e) { - _logger.Error($"EventManager: Failed to run event {sdkEvent} handler {e.Message}", e); + _logger.Error($"EventDelivery: Failed to run event {sdkEvent} handler {e.Message}", e); } } } diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 8f31e079..d353a1c0 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -26,23 +26,23 @@ public EventsManager() #region Public Methods public void Register(E sdkEvent, EventHandler handler) { - _activeSubscriptions.TryGetValue(sdkEvent, out var dict); - if (dict == null) + _activeSubscriptions.TryGetValue(sdkEvent, out var eventValues); + if (eventValues == null) { _activeSubscriptions.TryAdd(sdkEvent, new Dictionary() { {Triggered, false}, {EventHandler, handler} }); - _logger.Debug($"EventManager: Event {sdkEvent} is registered"); + _logger.Debug($"EventsManager: Event {sdkEvent} is registered"); } } public void Unregister(E sdkEvent) { if (_activeSubscriptions.ContainsKey(sdkEvent) - && _activeSubscriptions.TryGetValue(sdkEvent, out var dict) - && dict.Count > 0) + && _activeSubscriptions.TryGetValue(sdkEvent, out var eventValues) + && eventValues.Count > 0) { _activeSubscriptions.TryRemove(sdkEvent, out _); } @@ -52,11 +52,11 @@ public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eve { lock (_lock) { - _logger.Debug($"EventHandler: Handling internal event {sdkInternalEvent}"); + _logger.Debug($"EventsManager: Handling internal event {sdkInternalEvent}"); foreach (E sdkEvent in eventsToNotify) { - _logger.Debug($"EventHandler: Firing Sdk event {sdkEvent}"); + _logger.Debug($"EventsManager: Firing Sdk event {sdkEvent}"); _eventDelivery.Deliver(sdkEvent, eventMetadata, GetEventHandler(sdkEvent)); SetSdkEventTriggered(sdkEvent); } @@ -83,7 +83,7 @@ public void UpdateSdkInternalEventStatus(I sdkInternalEvent, bool status) { _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, (_, oldValue) => status); - _logger.Debug($"EventManager: Internal Event {sdkInternalEvent} status is updated to {status}"); + _logger.Debug($"EventsManager: Internal Event {sdkInternalEvent} status is updated to {status}"); } #endregion From b61473342e075c3f36259b0b0224e510a6a506b5 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 16 Dec 2025 14:20:21 -0800 Subject: [PATCH 29/87] removed static config manager constructor --- src/Splitio/Domain/EventManagerConfigData.cs | 13 +++--- src/Splitio/Domain/EventsManagerConfig.cs | 40 ++++--------------- src/Splitio/Services/Common/EventDelivery.cs | 3 +- src/Splitio/Services/Common/EventsManager.cs | 23 +++++------ .../Common/EventsManagerConfigTests.cs | 2 +- .../Unit Tests/Common/EventsManagerTests.cs | 5 +-- 6 files changed, 29 insertions(+), 57 deletions(-) diff --git a/src/Splitio/Domain/EventManagerConfigData.cs b/src/Splitio/Domain/EventManagerConfigData.cs index a85e9ea5..1970f14c 100644 --- a/src/Splitio/Domain/EventManagerConfigData.cs +++ b/src/Splitio/Domain/EventManagerConfigData.cs @@ -1,14 +1,13 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; namespace Splitio.Domain { public class EventManagerConfigData { - public Dictionary> RequireAll { get; set; } - public Dictionary> RequireAny { get; set; } - public Dictionary> Prerequisites { get; set; } - public Dictionary> SuppressedBy { get; set; } - public Dictionary ExecutionLimits { get; set; } + public Dictionary> RequireAll { get; protected set ; } + public Dictionary> RequireAny { get; protected set; } + public Dictionary> Prerequisites { get; protected set; } + public Dictionary> SuppressedBy { get; protected set; } + public Dictionary ExecutionLimits { get; protected set; } } } diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 8bf66dae..e5731caf 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -2,27 +2,11 @@ namespace Splitio.Domain { - public class EventsManagerConfig + public class EventsManagerConfig : EventManagerConfigData { - public Dictionary> RequireAll { get; private set; } - public Dictionary> RequireAny { get; private set; } - public Dictionary> Prerequisites { get; private set; } - public Dictionary> SuppressedBy { get; private set; } - public Dictionary ExecutionLimits { get; private set; } - - private EventsManagerConfig( - EventManagerConfigData configManagerData) + public EventsManagerConfig() { - RequireAll = configManagerData.RequireAll; - RequireAny = configManagerData.RequireAny; - Prerequisites = configManagerData.Prerequisites; - SuppressedBy = configManagerData.SuppressedBy; - ExecutionLimits = configManagerData.ExecutionLimits; - } - - public static EventsManagerConfig BuildEventsManagerConfig() - { - Dictionary> requireAll = new Dictionary> + RequireAll = new Dictionary> { { SdkEvent.SdkReady, new HashSet @@ -32,7 +16,7 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; - Dictionary> prerequisites = new Dictionary> + Prerequisites = new Dictionary> { { SdkEvent.SdkUpdate, new HashSet @@ -42,9 +26,9 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; - Dictionary> requireAny = new Dictionary> + RequireAny = new Dictionary> { - { SdkEvent.SdkUpdate, new HashSet + { SdkEvent.SdkUpdate, new HashSet { SdkInternalEvent.RuleBasedSegmentsUpdated, SdkInternalEvent.FlagsUpdated, @@ -59,7 +43,7 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; - Dictionary> suppressedBy = new Dictionary> + SuppressedBy = new Dictionary> { { SdkEvent.SdkReadyTimeout, new HashSet { SdkEvent.SdkReady } @@ -67,20 +51,12 @@ public static EventsManagerConfig BuildEventsManagerConfig() } }; - Dictionary executionLimits = new Dictionary + ExecutionLimits = new Dictionary { { SdkEvent.SdkReadyTimeout, -1 }, { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; - return new EventsManagerConfig(new EventManagerConfigData - { - Prerequisites = prerequisites, - ExecutionLimits = executionLimits, - SuppressedBy = suppressedBy, - RequireAll = requireAll, - RequireAny = requireAny - }); } } } diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 34bd2ca6..4a77c482 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,5 +1,4 @@ -using Splitio.Domain; -using Splitio.Services.Logger; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index d353a1c0..e5b6cd6d 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -26,25 +26,24 @@ public EventsManager() #region Public Methods public void Register(E sdkEvent, EventHandler handler) { - _activeSubscriptions.TryGetValue(sdkEvent, out var eventValues); - if (eventValues == null) + if (_activeSubscriptions.TryGetValue(sdkEvent, out var _)) { - _activeSubscriptions.TryAdd(sdkEvent, new Dictionary() - { - {Triggered, false}, - {EventHandler, handler} - }); - _logger.Debug($"EventsManager: Event {sdkEvent} is registered"); + return; } + + _activeSubscriptions.TryAdd(sdkEvent, new Dictionary() + { + {Triggered, false}, + {EventHandler, handler} + }); + _logger.Debug($"EventsManager: Event {sdkEvent} is registered"); } public void Unregister(E sdkEvent) { - if (_activeSubscriptions.ContainsKey(sdkEvent) - && _activeSubscriptions.TryGetValue(sdkEvent, out var eventValues) - && eventValues.Count > 0) + if (_activeSubscriptions.TryRemove(sdkEvent, out _)) { - _activeSubscriptions.TryRemove(sdkEvent, out _); + _logger.Debug($"EventsManager: Event {sdkEvent} is Unregistered"); } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index ef765289..899159b7 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -11,7 +11,7 @@ public class EventsManagerConfigTests public void BuildInstance() { //Act - EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + EventsManagerConfig config = new EventsManagerConfig(); //Assert config.RequireAll.TryGetValue(SdkEvent.SdkReady, out var require1); diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index bc4bef7a..163298bf 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -1,10 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; -using Splitio.Redis.Services.Shared; using Splitio.Services.Common; using System; using System.Collections.Generic; -using Splitio.Util; namespace Splitio_Tests.Unit_Tests.Common { @@ -23,7 +21,7 @@ public class EventsManagerTests public void TestFiringEvents() { //Act - EventsManagerConfig config = EventsManagerConfig.BuildEventsManagerConfig(); + EventsManagerConfig config = new EventsManagerConfig(); EventsManager eventsManager = new EventsManager(); Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); @@ -136,6 +134,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); eventsManager.Unregister(SdkEvent.SdkUpdate); + eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, From a5e771fada439a265e4916873c4002aa41bf0850 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 08:49:28 -0800 Subject: [PATCH 30/87] polish --- src/Splitio/Services/Common/EventDelivery.cs | 2 +- src/Splitio/Services/Common/EventsManager.cs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 4a77c482..be28dd36 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -6,7 +6,7 @@ namespace Splitio.Services.Common { public class EventDelivery : IEventDelivery { - private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); + private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index e5b6cd6d..f9f2593a 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -89,26 +89,26 @@ public void UpdateSdkInternalEventStatus(I sdkInternalEvent, bool status) #region Private Methods private void SetSdkEventTriggered(E sdkEvent) { - if (!_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) + if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { return; } - if ((bool)dict[Triggered]) + if ((bool)eventData[Triggered]) { return; } - Dictionary dict2 = new Dictionary(dict); - dict2[Triggered] = true; - _activeSubscriptions.TryUpdate(sdkEvent, dict2, dict); + Dictionary newEventData = new Dictionary(eventData); + newEventData[Triggered] = true; + _activeSubscriptions.TryUpdate(sdkEvent, newEventData, eventData); } private EventHandler GetEventHandler(E sdkEvent) { - if (_activeSubscriptions.TryGetValue(sdkEvent, out var dict)) + if (_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { - dict.TryGetValue(EventHandler, out var handler); + eventData.TryGetValue(EventHandler, out var handler); return (EventHandler)handler; } return null; From 1bc8bfd361633cd1f7326cafefc1800bb06783e6 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 09:48:20 -0800 Subject: [PATCH 31/87] added config as a parameter to events manager to be used by helper --- src/Splitio/Services/Common/EventsManager.cs | 7 +++-- src/Splitio/Util/Helper.cs | 31 +++++++++---------- .../Unit Tests/Common/EventsManagerTests.cs | 28 ++++++++--------- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index f9f2593a..12125083 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -1,4 +1,5 @@ -using Splitio.Services.Logger; +using Splitio.Domain; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; using System.Collections.Concurrent; @@ -15,12 +16,14 @@ public class EventsManager : IEventsManager private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); private readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); + public EventsManagerConfig ManagerConfig { get; private set; } - public EventsManager() + public EventsManager(EventsManagerConfig eventsManagerConfig) { _activeSubscriptions = new ConcurrentDictionary>(); _internalEventsStatus = new ConcurrentDictionary(); _eventDelivery = new EventDelivery(); + ManagerConfig = eventsManagerConfig; } #region Public Methods diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index 4abce8d9..c9854f23 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -92,8 +92,7 @@ public static string getFallbackConfig(FallbackTreatment fallbackTreatment) return null; } - public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent, - EventsManagerConfig eventsManagerConfig, + public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent, EventsManager eventsManager) { ValidSdkEvent finalSdkEvent = new ValidSdkEvent @@ -104,17 +103,17 @@ public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInterna eventsManager.UpdateSdkInternalEventStatus(sdkInternalEvent, true); List eventsToFire = new List(); - ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent, eventsManagerConfig); + ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent, eventsManager.ManagerConfig); if (requireAnySdkEvent.Valid) { if ((!eventsManager.EventAlreadyTriggered(requireAnySdkEvent.SdkEvent) - && ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManagerConfig) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManagerConfig) == -1) + && ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManager.ManagerConfig) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManager.ManagerConfig) == -1) { finalSdkEvent.SdkEvent = requireAnySdkEvent.SdkEvent; } - finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent, eventsManagerConfig, eventsManager) - && CheckSuppressedBy(finalSdkEvent.SdkEvent, eventsManagerConfig, eventsManager); + finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent, eventsManager) + && CheckSuppressedBy(finalSdkEvent.SdkEvent, eventsManager); } if (finalSdkEvent.Valid) @@ -122,7 +121,7 @@ public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInterna eventsToFire.Add(finalSdkEvent.SdkEvent); } - foreach (SdkEvent sdkEvent in CheckRequireAll(eventsManagerConfig, eventsManager)) + foreach (SdkEvent sdkEvent in CheckRequireAll(eventsManager)) { eventsToFire.Add(sdkEvent); } @@ -130,11 +129,11 @@ public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInterna return eventsToFire; } - private static List CheckRequireAll(EventsManagerConfig eventsManagerConfig, + private static List CheckRequireAll( EventsManager eventsManager) { List events = new List(); - foreach (KeyValuePair> kvp in eventsManagerConfig.RequireAll) + foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.RequireAll) { bool finalStatus = true; foreach (var val in kvp.Value) @@ -142,9 +141,9 @@ private static List CheckRequireAll(EventsManagerConfig eventsManagerC finalStatus &= eventsManager.GetSdkInternalEventStatus(val); } if (finalStatus - && CheckPrerequisites(kvp.Key, eventsManagerConfig, eventsManager) - && ((ExecutionLimit(kvp.Key, eventsManagerConfig) == 1 && !eventsManager.EventAlreadyTriggered(kvp.Key)) - || (ExecutionLimit(kvp.Key, eventsManagerConfig) == -1)) + && CheckPrerequisites(kvp.Key, eventsManager) + && ((ExecutionLimit(kvp.Key, eventsManager.ManagerConfig) == 1 && !eventsManager.EventAlreadyTriggered(kvp.Key)) + || (ExecutionLimit(kvp.Key, eventsManager.ManagerConfig) == -1)) && kvp.Value.Count > 0) { events.Add(kvp.Key); @@ -154,10 +153,10 @@ private static List CheckRequireAll(EventsManagerConfig eventsManagerC return events; } - private static bool CheckPrerequisites(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig, + private static bool CheckPrerequisites(SdkEvent sdkEvent, EventsManager eventsManager) { - foreach (KeyValuePair> kvp in eventsManagerConfig.Prerequisites) + foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.Prerequisites) { if (kvp.Key == sdkEvent) { @@ -173,10 +172,10 @@ private static bool CheckPrerequisites(SdkEvent sdkEvent, EventsManagerConfig ev return true; } - private static bool CheckSuppressedBy(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig, + private static bool CheckSuppressedBy(SdkEvent sdkEvent, EventsManager eventsManager) { - foreach (KeyValuePair> kvp in eventsManagerConfig.SuppressedBy) + foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.SuppressedBy) { if (kvp.Key == sdkEvent) { diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 163298bf..79f11f1a 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -22,7 +22,7 @@ public void TestFiringEvents() { //Act EventsManagerConfig config = new EventsManagerConfig(); - EventsManager eventsManager = new EventsManager(); + EventsManager eventsManager = new EventsManager(config); Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); PublicSdkReadyHandler += sdkReady_callback; @@ -39,16 +39,16 @@ public void TestFiringEvents() eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - config, eventsManager)); + eventsManager)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - config, eventsManager)); + eventsManager)); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - config, eventsManager)); + eventsManager)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - config, eventsManager)); + eventsManager)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); @@ -56,7 +56,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); @@ -65,7 +65,7 @@ public void TestFiringEvents() eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); @@ -74,7 +74,7 @@ public void TestFiringEvents() ResetAllVariables(); List eventsToNotify = Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, - config, eventsManager); + eventsManager); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData), eventsToNotify); System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); @@ -87,7 +87,7 @@ public void TestFiringEvents() eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); @@ -96,7 +96,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -106,7 +106,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -116,7 +116,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -126,7 +126,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -138,7 +138,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - config, eventsManager)); + eventsManager)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); From d4a630e5fb9c8b5a9d8f3dd4cb4f29b1f6c4f8be Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 12:53:50 -0800 Subject: [PATCH 32/87] replace event prop dict with struct --- src/Splitio/Services/Common/EventsManager.cs | 36 +++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 12125083..acb23688 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -9,9 +9,12 @@ namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - private readonly ConcurrentDictionary> _activeSubscriptions; - private readonly string Triggered = "Triggered"; - private readonly string EventHandler = "EventHandler"; + private struct PublicEventProperties + { + public bool Triggered; + public EventHandler EventHandler; + } + private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); private readonly EventDelivery _eventDelivery; @@ -20,7 +23,7 @@ public class EventsManager : IEventsManager public EventsManager(EventsManagerConfig eventsManagerConfig) { - _activeSubscriptions = new ConcurrentDictionary>(); + _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); _eventDelivery = new EventDelivery(); ManagerConfig = eventsManagerConfig; @@ -34,10 +37,10 @@ public void Register(E sdkEvent, EventHandler handler) return; } - _activeSubscriptions.TryAdd(sdkEvent, new Dictionary() + _activeSubscriptions.TryAdd(sdkEvent, new PublicEventProperties { - {Triggered, false}, - {EventHandler, handler} + Triggered = false, + EventHandler = handler }); _logger.Debug($"EventsManager: Event {sdkEvent} is registered"); } @@ -67,10 +70,9 @@ public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eve public bool EventAlreadyTriggered(E sdkEvent) { - if (_activeSubscriptions.TryGetValue(sdkEvent, out Dictionary triggered)) + if (_activeSubscriptions.TryGetValue(sdkEvent, out PublicEventProperties eventProperties)) { - triggered.TryGetValue(Triggered, out var trig); - return (bool)trig; + return eventProperties.Triggered; } return false; } @@ -97,24 +99,24 @@ private void SetSdkEventTriggered(E sdkEvent) return; } - if ((bool)eventData[Triggered]) + if (eventData.Triggered) { return; } - Dictionary newEventData = new Dictionary(eventData); - newEventData[Triggered] = true; + PublicEventProperties newEventData = eventData; + newEventData.Triggered = true; _activeSubscriptions.TryUpdate(sdkEvent, newEventData, eventData); } private EventHandler GetEventHandler(E sdkEvent) { - if (_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) + if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { - eventData.TryGetValue(EventHandler, out var handler); - return (EventHandler)handler; + return null; } - return null; + + return eventData.EventHandler; } #endregion } From 9ab18e2bad1d25a8482a827dee4d242c902043f6 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 12:57:45 -0800 Subject: [PATCH 33/87] added firing sdk events to split cache --- src/Splitio/Constants/Constants.cs | 7 +- .../Cache/Classes/InMemorySplitCache.cs | 18 ++++- .../Services/Client/Classes/JSONFileClient.cs | 5 +- .../Client/Classes/LocalhostClient.cs | 5 +- .../Client/Classes/SelfRefreshingClient.cs | 8 +- src/Splitio/Services/Common/EventsManager.cs | 36 +++++---- .../TargetingRulesFetcherTests.cs | 9 ++- .../Cache/InMemory/SplitCacheAsyncTests.cs | 66 +++++++++++++++- .../Cache/InMemory/SplitCacheTests.cs | 79 ++++++++++++++++--- .../Unit Tests/Common/EventsManagerTests.cs | 4 +- 10 files changed, 199 insertions(+), 38 deletions(-) diff --git a/src/Splitio/Constants/Constants.cs b/src/Splitio/Constants/Constants.cs index 408dfc32..f728b179 100644 --- a/src/Splitio/Constants/Constants.cs +++ b/src/Splitio/Constants/Constants.cs @@ -1,7 +1,7 @@ namespace Splitio.Constants { public static class Push - { + { public static string ControlPri => "control_pri"; public static string ControlSec => "control_sec"; public static string OccupancyPrefix => "[?occupancy=metrics.publishers]"; @@ -61,4 +61,9 @@ public static class ApiVersions public static string Spec1_1 => "1.1"; public static string LatestFlagsSpec => "1.3"; } + + public static class EventMetadataKeys + { + public static string Flags => "flags"; + } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index 8bbf3529..bd3f53c0 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Splitio.Services.Common; +using Splitio.Constants; namespace Splitio.Services.Cache.Classes { @@ -18,11 +20,12 @@ public class InMemorySplitCache : IFeatureFlagCache private readonly ConcurrentDictionary _featureFlags; private readonly ConcurrentDictionary _trafficTypes; private readonly ConcurrentDictionary> _flagSets; + private readonly EventsManager _eventsManager; private long _changeNumber; public InMemorySplitCache(ConcurrentDictionary featureFlags, - IFlagSetsFilter flagSetsFilter, + IFlagSetsFilter flagSetsFilter, EventsManager eventsManger, long changeNumber = -1) { _featureFlags = featureFlags; @@ -30,6 +33,7 @@ public InMemorySplitCache(ConcurrentDictionary featureFlags _changeNumber = changeNumber; _trafficTypes = new ConcurrentDictionary(); _flagSets = new ConcurrentDictionary>(); + _eventsManager = eventsManger; if (!_featureFlags.IsEmpty) { @@ -47,6 +51,8 @@ public InMemorySplitCache(ConcurrentDictionary featureFlags #region Sync Methods public void Update(List toAdd, List toRemove, long till) { + List eventsFlags = new List(); + foreach (var featureFlag in toAdd) { if (_featureFlags.TryGetValue(featureFlag.name, out ParsedSplit existing)) @@ -56,6 +62,7 @@ public void Update(List toAdd, List toRemove, long till) } _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); + eventsFlags.Add(featureFlag.name); IncreaseTrafficTypeCount(featureFlag.trafficTypeName); AddToFlagSets(featureFlag); @@ -71,6 +78,10 @@ public void Update(List toAdd, List toRemove, long till) } SetChangeNumber(till); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, + new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, eventsFlags } }), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, + _eventsManager)); } public void SetChangeNumber(long changeNumber) @@ -142,6 +153,11 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) featureFlag.changeNumber = changeNumber; _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, + new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, new List { { featureFlag.name } } } }), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, + _eventsManager)); + } public List GetSplitNames() diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index f6bdc593..36a5897a 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -1,6 +1,7 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Events.Interfaces; using Splitio.Services.Impressions.Classes; @@ -20,6 +21,7 @@ public class JSONFileClient : SplitClient { private readonly IFeatureFlagCache _featureFlagCache; private readonly ISegmentCache _segmentCache; + private EventsManager _eventsManager; public JSONFileClient(string splitsFilePath, string segmentsFilePath, @@ -53,8 +55,9 @@ public JSONFileClient(string splitsFilePath, } BuildFlagSetsFilter(new HashSet()); + _eventsManager = new EventsManager(new EventsManagerConfig()); - _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter); + _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _eventsManager); _impressionsLog = impressionsLog; _eventsLog = eventsLog; _trafficTypeValidator = trafficTypeValidator; diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index c1a9fbd3..deb1bda1 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -1,6 +1,7 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Impressions.Classes; using Splitio.Services.InputValidation.Classes; @@ -24,6 +25,7 @@ public class LocalhostClient : SplitClient private readonly IFeatureFlagCache _featureFlagCache; private readonly ILocalhostFileSync _localhostFileSync; private readonly string _fullPath; + private EventsManager _eventsManager; private readonly object _lock = new object(); @@ -46,8 +48,9 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm BuildFlagSetsFilter(new HashSet()); + _eventsManager = new EventsManager(new EventsManagerConfig()); var splits = _localhostFileService.ParseSplitFile(_fullPath); - _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter); + _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); if (configs.FileSync != null) diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index e3887905..04594e4d 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -52,6 +52,7 @@ public class SelfRefreshingClient : SplitClient private IRuleBasedSegmentCache _ruleBasedSegmentCache; private IUpdater _ruleBasedSegmentUpdater; private readonly new FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private EventsManager _eventsManager; public SelfRefreshingClient(string apiKey, ConfigurationOptions config, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(apiKey, fallbackTreatmentCalculator) @@ -60,6 +61,7 @@ public SelfRefreshingClient(string apiKey, ConfigurationOptions config, _fallbackTreatmentCalculator = fallbackTreatmentCalculator; BuildFlagSetsFilter(_config.FlagSetsFilter); + BuildEventsManager(); BuildSplitCache(); BuildSegmentCache(); BuildRuleBasedSegmentCache(); @@ -88,9 +90,13 @@ public SelfRefreshingClient(string apiKey, ConfigurationOptions config, } #region Private Methods + private void BuildEventsManager() + { + _eventsManager = new EventsManager(new EventsManagerConfig()); + } private void BuildSplitCache() { - _featureFlagCache = new InMemorySplitCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _flagSetsFilter); + _featureFlagCache = new InMemorySplitCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _flagSetsFilter, _eventsManager); } private void BuildSegmentCache() diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 12125083..acb23688 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -9,9 +9,12 @@ namespace Splitio.Services.Common { public class EventsManager : IEventsManager { - private readonly ConcurrentDictionary> _activeSubscriptions; - private readonly string Triggered = "Triggered"; - private readonly string EventHandler = "EventHandler"; + private struct PublicEventProperties + { + public bool Triggered; + public EventHandler EventHandler; + } + private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); private readonly EventDelivery _eventDelivery; @@ -20,7 +23,7 @@ public class EventsManager : IEventsManager public EventsManager(EventsManagerConfig eventsManagerConfig) { - _activeSubscriptions = new ConcurrentDictionary>(); + _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); _eventDelivery = new EventDelivery(); ManagerConfig = eventsManagerConfig; @@ -34,10 +37,10 @@ public void Register(E sdkEvent, EventHandler handler) return; } - _activeSubscriptions.TryAdd(sdkEvent, new Dictionary() + _activeSubscriptions.TryAdd(sdkEvent, new PublicEventProperties { - {Triggered, false}, - {EventHandler, handler} + Triggered = false, + EventHandler = handler }); _logger.Debug($"EventsManager: Event {sdkEvent} is registered"); } @@ -67,10 +70,9 @@ public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eve public bool EventAlreadyTriggered(E sdkEvent) { - if (_activeSubscriptions.TryGetValue(sdkEvent, out Dictionary triggered)) + if (_activeSubscriptions.TryGetValue(sdkEvent, out PublicEventProperties eventProperties)) { - triggered.TryGetValue(Triggered, out var trig); - return (bool)trig; + return eventProperties.Triggered; } return false; } @@ -97,24 +99,24 @@ private void SetSdkEventTriggered(E sdkEvent) return; } - if ((bool)eventData[Triggered]) + if (eventData.Triggered) { return; } - Dictionary newEventData = new Dictionary(eventData); - newEventData[Triggered] = true; + PublicEventProperties newEventData = eventData; + newEventData.Triggered = true; _activeSubscriptions.TryUpdate(sdkEvent, newEventData, eventData); } private EventHandler GetEventHandler(E sdkEvent) { - if (_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) + if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { - eventData.TryGetValue(EventHandler, out var handler); - return (EventHandler)handler; + return null; } - return null; + + return eventData.EventHandler; } #endregion } diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index 15c1b674..52c5cb4f 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -44,7 +44,8 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); var gates = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); @@ -89,7 +90,8 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAll var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging_4.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); var gates = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); @@ -149,7 +151,8 @@ public async Task ExecuteGetWithoutResults() var segmentFetcher = new SelfRefreshingSegmentFetcher(apiSegmentChangeFetcher, segmentCache, segmentsQueue, segmentsTask, gates); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary()); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 3000); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); var rbsParser = new RuleBasedSegmentParser(segmentCache, segmentFetcher); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 3c4541e9..5d3b4c18 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -2,7 +2,9 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using Splitio.Services.Filters; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -15,13 +17,19 @@ public class SplitCacheAsyncTests { private readonly IFlagSetsFilter _flagSetsFilter; private readonly IFeatureFlagCache _cache; + private readonly EventsManager _eventsManager; + private bool SdkUpdate = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; public SplitCacheAsyncTests() { _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); + _eventsManager = new EventsManager(new EventsManagerConfig()); + Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); - _cache = new InMemorySplitCache(splits, _flagSetsFilter); + _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); } [TestMethod] @@ -169,5 +177,61 @@ public async Task GetSplitNamesAsyncReturnsItems() // Assert. Assert.AreEqual(5, result.Count); } + + [TestMethod] + public async Task NotifyUpdateEventTest() + { + // Arrange. + var toAdd = new List(); + var toNotify = new List(); + for (int i = 1; i <= 5; i++) + { + toAdd.Add(new ParsedSplit + { + name = $"feature-flag-{i}", + defaultTreatment = "on", + changeNumber = i + }); + toNotify.Add($"feature-flag-{i}"); + } + PublicSdkUpdateHandler += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + + SdkUpdate = false; + _cache.Update(toAdd, new List(), -1); + + // Act. + var result = await _cache.GetSplitNamesAsync(); + + // Assert. + Assert.AreEqual(5, result.Count); + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); + List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; + Assert.IsTrue(flags.Count == 5); + for (int i = 1; i <= 5; i++) + { + Assert.IsTrue(flags.Contains($"feature-flag-{i}")); + } + + SdkUpdate = false; + eMetadata = null; + _cache.Kill(123, "feature-flag-1", "off"); + + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); + flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; + Assert.IsTrue(flags.Count == 1); + Assert.IsTrue(flags.Contains($"feature-flag-1")); + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + eMetadata = metadata; + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 6d0f2411..35a59f45 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -2,7 +2,9 @@ using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; +using Splitio.Services.Common; using Splitio.Services.Filters; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; @@ -13,6 +15,9 @@ namespace Splitio_Tests.Unit_Tests.Cache public class SplitCacheTests { private readonly Mock _flagSetsFilter; + private bool SdkUpdate = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; public SplitCacheTests() { @@ -23,7 +28,8 @@ public SplitCacheTests() public void AddAndGetSplitTest() { //Arrange - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; //Act @@ -38,7 +44,8 @@ public void AddAndGetSplitTest() public void AddDuplicateSplitTest() { //Arrange - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; //Act @@ -58,7 +65,8 @@ public void AddDuplicateSplitTest() public void GetInexistentSplitTest() { //Arrange - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; //Act @@ -75,7 +83,8 @@ public void RemoveSplitTest() var splitName = "test1"; var splits = new ConcurrentDictionary(); splits.TryAdd(splitName, new ParsedSplit() { name = splitName }); - var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager); //Act splitCache.Update(new List(), new List { splitName }, -1); @@ -89,7 +98,8 @@ public void RemoveSplitTest() public void SetAndGetChangeNumberTest() { //Arrange - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var changeNumber = 1234; //Act @@ -104,7 +114,8 @@ public void SetAndGetChangeNumberTest() public void GetAllSplitsTest() { //Arrange - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; var splitName2 = "test2"; @@ -123,7 +134,8 @@ public void GetAllSplitsTest() public void AddOrUpdate_WhenUpdateTraffictType_ReturnsTrue() { // Arrange - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "split_1"; var splitName2 = "split_2"; @@ -165,7 +177,8 @@ public void GetNamesByFlagSetsWithoutFilter() Sets = new HashSet { "set1", "set2" } }); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet())); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -208,8 +221,8 @@ public void GetNamesByFlagSetsWithFilters() defaultTreatment = "on", Sets = new HashSet { "set1", "set2" } }); - - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" })); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -226,5 +239,51 @@ public void GetNamesByFlagSetsWithFilters() var set4 = result["set4"]; Assert.IsFalse(set4.Any()); } + + [TestMethod] + public void NotifyUpdateEventTest() + { + // Arrange. + var eventsManager = new EventsManager(new EventsManagerConfig()); + Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + var splitName = "test1"; + + var toNotify = new List { { splitName } }; + PublicSdkUpdateHandler += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, eventsManager)); + + // Act. + SdkUpdate = false; + splitCache.Update(new List { new ParsedSplit() { name = splitName } }, new List(), -1); + + // Assert. + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); + List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; + Assert.IsTrue(flags.Count == 1); + Assert.IsTrue(flags.Contains(splitName)); + + // Act. + SdkUpdate = false; + eMetadata = null; + splitCache.Kill(123, splitName, "off"); + + // Assert. + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); + flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; + Assert.IsTrue(flags.Count == 1); + Assert.IsTrue(flags.Contains(splitName)); + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + eMetadata = metadata; + } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 79f11f1a..558fa68c 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -155,8 +155,8 @@ void ResetAllVariables() void VerifyMetadata(EventMetadata eMetdata) { - Assert.IsTrue(eMetadata.ContainKey("flags")); - List flags = (List)eMetadata.GetData()["flags"]; + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); + List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); Assert.IsTrue(flags.Contains("flag1")); } From bb47dd251d4a7c4b8932ccd83b2a30ecbc97d7e0 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 15:32:44 -0800 Subject: [PATCH 34/87] polish --- src/Splitio/Services/Client/Classes/JSONFileClient.cs | 5 ++--- src/Splitio/Services/Client/Classes/LocalhostClient.cs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index 36a5897a..2ef9df66 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -21,7 +21,6 @@ public class JSONFileClient : SplitClient { private readonly IFeatureFlagCache _featureFlagCache; private readonly ISegmentCache _segmentCache; - private EventsManager _eventsManager; public JSONFileClient(string splitsFilePath, string segmentsFilePath, @@ -55,9 +54,9 @@ public JSONFileClient(string splitsFilePath, } BuildFlagSetsFilter(new HashSet()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig()); - _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _eventsManager); + _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, eventsManager); _impressionsLog = impressionsLog; _eventsLog = eventsLog; _trafficTypeValidator = trafficTypeValidator; diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index deb1bda1..1afea359 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -25,7 +25,6 @@ public class LocalhostClient : SplitClient private readonly IFeatureFlagCache _featureFlagCache; private readonly ILocalhostFileSync _localhostFileSync; private readonly string _fullPath; - private EventsManager _eventsManager; private readonly object _lock = new object(); @@ -48,9 +47,9 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm BuildFlagSetsFilter(new HashSet()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig()); var splits = _localhostFileService.ParseSplitFile(_fullPath); - _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); + _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, eventsManager); if (configs.FileSync != null) From 73c8746e47648433d0b6f846b40adb507f3c9906 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 15:41:19 -0800 Subject: [PATCH 35/87] added event notification to segments and rbsegments cache --- src/Splitio/Constants/Constants.cs | 2 + .../Classes/InMemoryRuleBasedSegmentCache.cs | 13 +++- .../Cache/Classes/InMemorySegmentCache.cs | 16 ++++- .../Services/Client/Classes/JSONFileClient.cs | 5 +- .../Client/Classes/LocalhostClient.cs | 5 +- .../Client/Classes/SelfRefreshingClient.cs | 4 +- .../SelfRefreshingSegmentFetcherTests.cs | 4 +- .../TargetingRulesFetcherTests.cs | 18 ++--- .../InMemory/RuleBasedSegmentCacheTests.cs | 44 ++++++++++++- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 41 +++++++++++- .../Cache/InMemory/SegmentCacheTests.cs | 65 +++++++++++++++++-- .../UserDefinedSegmentMatcherAsyncTests.cs | 25 ++++--- .../UserDefinedSegmentMatcherTests.cs | 25 ++++--- .../SelfRefreshingSegmentFetcherUnitTests.cs | 4 +- .../SelfRefreshingSegmentUnitTests.cs | 7 +- 15 files changed, 230 insertions(+), 48 deletions(-) diff --git a/src/Splitio/Constants/Constants.cs b/src/Splitio/Constants/Constants.cs index f728b179..318606c6 100644 --- a/src/Splitio/Constants/Constants.cs +++ b/src/Splitio/Constants/Constants.cs @@ -65,5 +65,7 @@ public static class ApiVersions public static class EventMetadataKeys { public static string Flags => "flags"; + public static string Segments => "segments"; + public static string RuleBasedSegments => "ruleBasedSegments"; } } diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 554e2035..2517fc69 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -1,5 +1,7 @@ -using Splitio.Domain; +using Splitio.Constants; +using Splitio.Domain; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -10,12 +12,15 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache { private readonly ConcurrentDictionary _cache; private long _changeNumber; + private readonly EventsManager _eventsManager; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, + EventsManager eventsManger, long changeNumber = -1) { _cache = cache; _changeNumber = changeNumber; + _eventsManager = eventsManger; } #region Sync Methods @@ -45,9 +50,11 @@ public long GetChangeNumber() // Producer public void Update(List toAdd, List toRemove, long till) { + List toNotify = new List(); foreach (var rbSegment in toAdd) { _cache.AddOrUpdate(rbSegment.Name, rbSegment, (key, oldValue) => rbSegment); + toNotify.Add(rbSegment.Name); } foreach (var name in toRemove) @@ -56,6 +63,10 @@ public void Update(List toAdd, List toRemove, long til } SetChangeNumber(till); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, + new EventMetadata(new Dictionary { { EventMetadataKeys.RuleBasedSegments, toNotify } }), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, + _eventsManager)); } public void SetChangeNumber(long changeNumber) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index f94a3d51..7655a6e6 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -1,5 +1,7 @@ -using Splitio.Domain; +using Splitio.Constants; +using Splitio.Domain; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System.Collections.Concurrent; @@ -13,10 +15,12 @@ public class InMemorySegmentCache : ISegmentCache private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemorySegmentCache)); private readonly ConcurrentDictionary _segments; + private readonly EventsManager _eventsManager; - public InMemorySegmentCache(ConcurrentDictionary segments) + public InMemorySegmentCache(ConcurrentDictionary segments, EventsManager eventsManger) { _segments = segments; + _eventsManager = eventsManger; } #region Methods Sync @@ -31,6 +35,10 @@ public void AddToSegment(string segmentName, List segmentKeys) } segment.AddKeys(segmentKeys); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, + new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } }), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, + _eventsManager)); } public void RemoveFromSegment(string segmentName, List segmentKeys) @@ -38,6 +46,10 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) if (_segments.TryGetValue(segmentName, out Segment segment)) { segment.RemoveKeys(segmentKeys); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, + new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } }), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, + _eventsManager)); } } diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index 36a5897a..2ef9df66 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -21,7 +21,6 @@ public class JSONFileClient : SplitClient { private readonly IFeatureFlagCache _featureFlagCache; private readonly ISegmentCache _segmentCache; - private EventsManager _eventsManager; public JSONFileClient(string splitsFilePath, string segmentsFilePath, @@ -55,9 +54,9 @@ public JSONFileClient(string splitsFilePath, } BuildFlagSetsFilter(new HashSet()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig()); - _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _eventsManager); + _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, eventsManager); _impressionsLog = impressionsLog; _eventsLog = eventsLog; _trafficTypeValidator = trafficTypeValidator; diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index deb1bda1..1afea359 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -25,7 +25,6 @@ public class LocalhostClient : SplitClient private readonly IFeatureFlagCache _featureFlagCache; private readonly ILocalhostFileSync _localhostFileSync; private readonly string _fullPath; - private EventsManager _eventsManager; private readonly object _lock = new object(); @@ -48,9 +47,9 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm BuildFlagSetsFilter(new HashSet()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig()); var splits = _localhostFileService.ParseSplitFile(_fullPath); - _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); + _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, eventsManager); if (configs.FileSync != null) diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 04594e4d..33141a74 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -101,12 +101,12 @@ private void BuildSplitCache() private void BuildSegmentCache() { - _segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity)); + _segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _eventsManager); } private void BuildRuleBasedSegmentCache() { - _ruleBasedSegmentCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity)); + _ruleBasedSegmentCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _eventsManager); } private void BuildTelemetryStorage() diff --git a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs index 10cf9251..bde1a569 100644 --- a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Cache.Classes; +using Splitio.Services.Common; using Splitio.Services.SegmentFetcher.Classes; using System.Collections.Concurrent; @@ -26,7 +27,8 @@ public SelfRefreshingSegmentFetcherTests() public void ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index 52c5cb4f..f2b7dfe7 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -38,13 +38,13 @@ public TargetingRulesFetcherTests() public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); - var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); - var eventsManager = new EventsManager(new EventsManagerConfig()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); var gates = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(gates); @@ -84,13 +84,13 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAllocation() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); - var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging_4.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); - var eventsManager = new EventsManager(new EventsManagerConfig()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); var gates = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(gates); @@ -142,16 +142,16 @@ public async Task ExecuteGetWithoutResults() var sdkSegmentApiClient = new SegmentSdkApiClient(httpClient, telemetryStorage, baseUrl); var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); var gates = new InMemoryReadinessGatesCache(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(4, segmentsQueue); segmentsQueue.AddObserver(worker); var segmentsTask = taskManager.NewPeriodicTask(Splitio.Enums.Task.SegmentsFetcher, 3000); var segmentFetcher = new SelfRefreshingSegmentFetcher(apiSegmentChangeFetcher, segmentCache, segmentsQueue, segmentsTask, gates); - var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary()); + var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); - var eventsManager = new EventsManager(new EventsManagerConfig()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 3000); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index 763ac6eb..e3ba2df2 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -1,6 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Cache.Classes; +using Splitio.Services.Common; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -11,12 +13,17 @@ namespace Splitio_Tests.Unit_Tests.Cache.InMemory public class RuleBasedSegmentCacheTests { private InMemoryRuleBasedSegmentCache _segmentCache; + private EventsManager _eventsManager; + private bool SdkUpdate = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; [TestInitialize] public void Setup() { var cache = new ConcurrentDictionary(); - _segmentCache = new InMemoryRuleBasedSegmentCache(cache); + _eventsManager = new EventsManager(new EventsManagerConfig()); + _segmentCache = new InMemoryRuleBasedSegmentCache(cache, _eventsManager); } [TestMethod] @@ -142,5 +149,40 @@ public void Contains_ShouldReturnTrue() Assert.IsFalse(_segmentCache.Contains(new List { "segment1", "segment3" })); Assert.IsTrue(_segmentCache.Contains(new List { "segment1", "segment2" })); } + + [TestMethod] + public void Update_ShouldNotifyEvent() + { + // Arrange + Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); + + var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; + var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; + var till = 67890; + var toNotify = new List { { "segment-to-add" } }; + PublicSdkUpdateHandler += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + + // Act + SdkUpdate = false; + _segmentCache.Update(new List { segmentToAdd, segmentToRemove }, new List { segmentToRemove.Name }, till); + + // Assert + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); + List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; + Assert.IsTrue(rbsegments.Count == 2); + Assert.IsTrue(rbsegments.Contains("segment-to-add")); + Assert.IsTrue(rbsegments.Contains("segment-to-remove")); + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + eMetadata = metadata; + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index c08a7515..806d67b2 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -2,9 +2,12 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; +using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Cache { @@ -12,12 +15,16 @@ namespace Splitio_Tests.Unit_Tests.Cache public class SegmentCacheAsyncTests { private readonly ISegmentCache _cache; + private EventsManager _eventsManager; + private bool SdkUpdate = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; public SegmentCacheAsyncTests() { var segments = new ConcurrentDictionary(); - - _cache = new InMemorySegmentCache(segments); + _eventsManager = new EventsManager(new EventsManagerConfig()); + _cache = new InMemorySegmentCache(segments, _eventsManager); } [TestMethod] @@ -47,5 +54,35 @@ public async Task IsInSegmentAsyncTestTrue() //Assert Assert.IsTrue(result); } + + [TestMethod] + public async Task NotifyEventsTest() + { + //Arrange + var segmentName = "segment_test"; + Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); + var toNotify = new List { { segmentName } }; + PublicSdkUpdateHandler += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + + //Act + SdkUpdate = false; + _cache.AddToSegment(segmentName, new List { "abcd", "zzzzf" }); + + //Assert + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); + string segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; + Assert.AreEqual(segmentName, segment); + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + eMetadata = metadata; + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index 287f1875..b81611a4 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -1,6 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Cache.Classes; +using Splitio.Services.Common; +using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -9,11 +11,16 @@ namespace Splitio_Tests.Unit_Tests.Cache [TestClass] public class SegmentCacheTests { + private bool SdkUpdate = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; + [TestMethod] public void RegisterSegmentTest() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "abcd", "1234" }; var segmentName = "test"; @@ -29,7 +36,8 @@ public void RegisterSegmentTest() public void IsNotInSegmentTest() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; @@ -45,7 +53,8 @@ public void IsNotInSegmentTest() public void IsInSegmentWithInexistentSegmentTest() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); //Act var result = segmentCache.IsInSegment("test", "abcd"); @@ -58,7 +67,8 @@ public void IsInSegmentWithInexistentSegmentTest() public void RemoveKeyFromSegmentTest() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; @@ -77,7 +87,8 @@ public void RemoveKeyFromSegmentTest() public void SetAndGetChangeNumberTest() { //Arrange - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentName = "test"; //Act @@ -88,5 +99,49 @@ public void SetAndGetChangeNumberTest() //Assert Assert.AreEqual(1234, result); } + + [TestMethod] + public void NotifyEventsTest() + { + //Arrange + var eventsManager = new EventsManager(new EventsManagerConfig()); + Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var keys = new List { "1234" }; + var segmentName = "test"; + var toNotify = new List { { segmentName } }; + PublicSdkUpdateHandler += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); + eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, eventsManager)); + + // Act + SdkUpdate = false; + segmentCache.AddToSegment(segmentName, keys); + + //Assert + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); + string segment = (string) eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; + Assert.AreEqual(segmentName, segment); + + // Act + SdkUpdate = false; + eMetadata = null; + segmentCache.RemoveFromSegment(segmentName, keys); + + //Assert + Assert.IsTrue(SdkUpdate); + Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); + segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; + Assert.AreEqual(segmentName, segment); + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + eMetadata = metadata; + } } } diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs index 1a7a087f..e870361b 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Cache.Classes; +using Splitio.Services.Common; using Splitio.Services.Parsing; using System.Collections.Concurrent; using System.Collections.Generic; @@ -22,7 +23,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -45,7 +47,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -62,7 +65,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -79,7 +83,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -101,7 +106,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -124,7 +130,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -141,7 +148,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -158,7 +166,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs index e3511399..11239973 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Concurrent; using Splitio.Services.Cache.Classes; +using Splitio.Services.Common; namespace Splitio_Tests.Unit_Tests { @@ -21,7 +22,8 @@ public void MatchShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -44,7 +46,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -61,7 +64,8 @@ public void MatchShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -78,7 +82,8 @@ public void MatchShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -100,7 +105,8 @@ public void MatchShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -123,7 +129,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -140,7 +147,8 @@ public void MatchShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -157,7 +165,8 @@ public void MatchShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index b2eac5b9..9e242cc8 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -4,6 +4,7 @@ using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.SegmentFetcher.Classes; using Splitio.Services.SegmentFetcher.Interfaces; using Splitio.Services.Shared.Classes; @@ -31,7 +32,8 @@ public void InitializeSegmentNotExistent() var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var cache = new InMemorySegmentCache(segments); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var cache = new InMemorySegmentCache(segments, eventsManager); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(5, segmentsQueue); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs index 228dc4c5..06f32feb 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs @@ -3,6 +3,7 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using Splitio.Services.SegmentFetcher.Classes; using Splitio.Services.SplitFetcher.Interfaces; using System; @@ -22,7 +23,8 @@ public async Task FetchSegmentNullChangesFetcherResponseShouldNotUpdateCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var cache = new InMemorySegmentCache(segments); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var cache = new InMemorySegmentCache(segments, eventsManager); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient @@ -44,7 +46,8 @@ public async Task FetchSegmentShouldUpdateSegmentsCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var cache = new InMemorySegmentCache(segments); + var eventsManager = new EventsManager(new EventsManagerConfig()); + var cache = new InMemorySegmentCache(segments, eventsManager); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient From 39fa4194d48c7e9dc09a38acb979d85a858b255f Mon Sep 17 00:00:00 2001 From: Bill Al Date: Wed, 17 Dec 2025 15:57:52 -0800 Subject: [PATCH 36/87] fixed building jsonlocal client --- src/Splitio/Services/Client/Classes/JSONFileClient.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index 2ef9df66..ebc40e1a 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -35,8 +35,9 @@ public JSONFileClient(string splitsFilePath, IRuleBasedSegmentCache ruleBasedSegmentCache = null ) : base("localhost", fallbackTreatmentCalculator) { - _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary()); - var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary()); + var eventsManager = new EventsManager(new EventsManagerConfig()); + _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher(segmentsFilePath, _segmentCache); var splitChangeFetcher = new JSONFileSplitChangeFetcher(splitsFilePath); @@ -54,7 +55,6 @@ public JSONFileClient(string splitsFilePath, } BuildFlagSetsFilter(new HashSet()); - var eventsManager = new EventsManager(new EventsManagerConfig()); _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, eventsManager); _impressionsLog = impressionsLog; From 2e361c1028bf6673f294b689e7f6c50ed67d0117 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 18 Dec 2025 12:36:06 -0800 Subject: [PATCH 37/87] added events for ready and timedout --- .../Services/Client/Classes/RedisClient.cs | 4 +- .../Classes/InMemoryReadinessGatesCache.cs | 15 ++- .../Services/Client/Classes/JSONFileClient.cs | 4 +- .../Client/Classes/LocalhostClient.cs | 4 +- .../Client/Classes/SelfRefreshingClient.cs | 11 +-- .../Services/Client/Classes/SplitClient.cs | 6 +- .../Services/Client/Classes/SplitFactory.cs | 9 +- .../SelfRefreshingBlockUntilReadyService.cs | 14 ++- .../BaseLocalhostClientTests.cs | 31 +++--- .../Integration Tests/InMemoryClientTests.cs | 5 +- .../Integration Tests/JSONFileClientTests.cs | 97 ++++++++++--------- .../Integration Tests/RedisClientTests.cs | 51 +++++----- .../TargetingRulesFetcherTests.cs | 6 +- .../Client/LocalhostClientForTesting.cs | 6 +- .../Client/LocalhostClientUnitTests.cs | 7 +- .../Client/SdkReadinessGatesUnitTests.cs | 33 ++++++- .../Client/SplitClientForTesting.cs | 5 +- .../Impressions/ImpressionsCounterTests.cs | 10 +- .../SelfRefreshingSegmentFetcherUnitTests.cs | 2 +- ...lfRefreshingBlockUntilReadyServiceTests.cs | 52 ++++++++++ .../EventSourceClientTests.cs | 2 +- .../Splitio.TestSupport/SplitClientForTest.cs | 4 +- 22 files changed, 255 insertions(+), 123 deletions(-) create mode 100644 tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs diff --git a/Splitio.Redis/Services/Client/Classes/RedisClient.cs b/Splitio.Redis/Services/Client/Classes/RedisClient.cs index 4cfc76ea..345a546d 100644 --- a/Splitio.Redis/Services/Client/Classes/RedisClient.cs +++ b/Splitio.Redis/Services/Client/Classes/RedisClient.cs @@ -9,6 +9,7 @@ using Splitio.Redis.Telemetry.Storages; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Evaluator; using Splitio.Services.Impressions.Classes; @@ -30,7 +31,8 @@ public class RedisClient : SplitClient private IFeatureFlagCacheConsumer _featureFlagCacheConsumer; private readonly new FallbackTreatmentCalculator _fallbackTreatmentCalculator; - public RedisClient(ConfigurationOptions config, string apiKey, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(apiKey, fallbackTreatmentCalculator) + public RedisClient(ConfigurationOptions config, string apiKey, FallbackTreatmentCalculator fallbackTreatmentCalculator, + EventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) { _config = new RedisConfig(); _fallbackTreatmentCalculator = fallbackTreatmentCalculator; diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index d1d42e51..d3121456 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -1,4 +1,7 @@ -using Splitio.Services.Cache.Interfaces; +using Splitio.Domain; +using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; +using System.Collections.Generic; using System.Threading; namespace Splitio.Services.Client.Classes @@ -7,6 +10,12 @@ public class InMemoryReadinessGatesCache : IStatusManager { private readonly CountdownEvent _sdkReady = new CountdownEvent(1); private readonly CountdownEvent _sdkDestroyed = new CountdownEvent(1); + private readonly EventsManager _eventsManager; + + public InMemoryReadinessGatesCache(EventsManager eventsManager) + { + _eventsManager = eventsManager; + } public bool IsReady() { @@ -21,6 +30,10 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, + new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, + _eventsManager)); } public void SetDestroy() diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index ebc40e1a..830f5a0f 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -25,6 +25,7 @@ public class JSONFileClient : SplitClient public JSONFileClient(string splitsFilePath, string segmentsFilePath, FallbackTreatmentCalculator fallbackTreatmentCalculator, + EventsManager eventsManager, ISegmentCache segmentCacheInstance = null, IFeatureFlagCache featureFlagCacheInstance = null, IImpressionsLog impressionsLog = null, @@ -33,9 +34,8 @@ public JSONFileClient(string splitsFilePath, ITrafficTypeValidator trafficTypeValidator = null, IImpressionsManager impressionsManager = null, IRuleBasedSegmentCache ruleBasedSegmentCache = null - ) : base("localhost", fallbackTreatmentCalculator) + ) : base("localhost", fallbackTreatmentCalculator, eventsManager) { - var eventsManager = new EventsManager(new EventsManagerConfig()); _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index 1afea359..b22c5f07 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -28,7 +28,8 @@ public class LocalhostClient : SplitClient private readonly object _lock = new object(); - public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base("localhost", fallbackTreatmentCalculator) + public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatmentCalculator fallbackTreatmentCalculator, + EventsManager eventsManager) : base("localhost", fallbackTreatmentCalculator, eventsManager) { var configs = (LocalhostClientConfigurations)_configService.ReadConfig(configurationOptions, ConfigTypes.Localhost, _statusManager); @@ -47,7 +48,6 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm BuildFlagSetsFilter(new HashSet()); - var eventsManager = new EventsManager(new EventsManagerConfig()); var splits = _localhostFileService.ParseSplitFile(_fullPath); _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, eventsManager); diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 33141a74..ce314289 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -55,13 +55,14 @@ public class SelfRefreshingClient : SplitClient private EventsManager _eventsManager; public SelfRefreshingClient(string apiKey, ConfigurationOptions config, - FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(apiKey, fallbackTreatmentCalculator) + FallbackTreatmentCalculator fallbackTreatmentCalculator, + EventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) { _config = (SelfRefreshingConfig)_configService.ReadConfig(config, ConfigTypes.InMemory); _fallbackTreatmentCalculator = fallbackTreatmentCalculator; + _eventsManager = eventsManager; BuildFlagSetsFilter(_config.FlagSetsFilter); - BuildEventsManager(); BuildSplitCache(); BuildSegmentCache(); BuildRuleBasedSegmentCache(); @@ -90,10 +91,6 @@ public SelfRefreshingClient(string apiKey, ConfigurationOptions config, } #region Private Methods - private void BuildEventsManager() - { - _eventsManager = new EventsManager(new EventsManagerConfig()); - } private void BuildSplitCache() { _featureFlagCache = new InMemorySplitCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _flagSetsFilter, _eventsManager); @@ -218,7 +215,7 @@ private void BuildManager() private void BuildBlockUntilReadyService() { - _blockUntilReadyService = new SelfRefreshingBlockUntilReadyService(_statusManager, _telemetryInitProducer); + _blockUntilReadyService = new SelfRefreshingBlockUntilReadyService(_statusManager, _telemetryInitProducer, _eventsManager); } private void BuildTelemetrySyncTask() diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 54297fdf..7f9c0fb0 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -64,9 +64,11 @@ public abstract class SplitClient : ISplitClient protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; - protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator) + protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, + EventsManager eventsManager) { ApiKey = apikey; + Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _wrapperAdapter = WrapperAdapter.Instance(); @@ -77,7 +79,7 @@ protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatme _factoryInstantiationsService = FactoryInstantiationsService.Instance(); _flagSetsValidator = new FlagSetsValidator(); _configService = new ConfigService(_wrapperAdapter, _flagSetsValidator, new SdkMetadataValidator()); - _statusManager = new InMemoryReadinessGatesCache(); + _statusManager = new InMemoryReadinessGatesCache(eventsManager); _tasksManager = new TasksManager(_statusManager); } diff --git a/src/Splitio/Services/Client/Classes/SplitFactory.cs b/src/Splitio/Services/Client/Classes/SplitFactory.cs index 92f8b46e..d22b6647 100644 --- a/src/Splitio/Services/Client/Classes/SplitFactory.cs +++ b/src/Splitio/Services/Client/Classes/SplitFactory.cs @@ -1,5 +1,6 @@ using Splitio.Domain; using Splitio.Services.Client.Interfaces; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.InputValidation.Classes; using Splitio.Services.InputValidation.Interfaces; @@ -59,6 +60,8 @@ public ISplitManager Manager() private void BuildSplitClient() { FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(_options.FallbackTreatments); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + switch (_options.Mode) { case Mode.Standalone: @@ -66,11 +69,11 @@ private void BuildSplitClient() if (_apiKey == "localhost") { - _client = new LocalhostClient(_options, fallbackTreatmentCalculator); + _client = new LocalhostClient(_options, fallbackTreatmentCalculator, eventsManager); } else { - _client = new SelfRefreshingClient(_apiKey, _options, fallbackTreatmentCalculator); + _client = new SelfRefreshingClient(_apiKey, _options, fallbackTreatmentCalculator, eventsManager); } break; case Mode.Consumer: @@ -81,7 +84,7 @@ private void BuildSplitClient() var redisAssembly = Assembly.Load(new AssemblyName("Splitio.Redis")); var redisType = redisAssembly.GetType("Splitio.Redis.Services.Client.Classes.RedisClient"); - _client = (ISplitClient)Activator.CreateInstance(redisType, new object[] { _options, _apiKey, fallbackTreatmentCalculator }); + _client = (ISplitClient)Activator.CreateInstance(redisType, new object[] { _options, _apiKey, fallbackTreatmentCalculator, eventsManager }); } catch (ArgumentException ex) { diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index fcc27eec..6bf5c2b9 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -1,8 +1,11 @@ -using Splitio.Services.Cache.Interfaces; +using Splitio.Domain; +using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; using Splitio.Services.Logger; using Splitio.Services.Shared.Interfaces; using Splitio.Telemetry.Storages; using System; +using System.Collections.Generic; namespace Splitio.Services.Shared.Classes { @@ -12,11 +15,14 @@ public class SelfRefreshingBlockUntilReadyService : IBlockUntilReadyService private readonly IStatusManager _statusManager; private readonly ITelemetryInitProducer _telemetryInitProducer; + private readonly EventsManager _eventsManager; - public SelfRefreshingBlockUntilReadyService(IStatusManager statusManager, ITelemetryInitProducer telemetryInitProducer) + public SelfRefreshingBlockUntilReadyService(IStatusManager statusManager, ITelemetryInitProducer telemetryInitProducer, + EventsManager eventsManager) { _statusManager = statusManager; _telemetryInitProducer = telemetryInitProducer; + _eventsManager = eventsManager; } public void BlockUntilReady(int blockMilisecondsUntilReady) @@ -30,6 +36,10 @@ public void BlockUntilReady(int blockMilisecondsUntilReady) if (!_statusManager.WaitUntilReady(blockMilisecondsUntilReady)) { + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, + new EventMetadata(new Dictionary()), + Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, + _eventsManager)); _telemetryInitProducer.RecordBURTimeout(); throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady} milliseconds"); } diff --git a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs index 4f035f95..fe9b3227 100644 --- a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs @@ -2,6 +2,7 @@ using Splitio.Domain; using Splitio.Redis.Services.Client.Classes; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Telemetry.Domain; using System; @@ -24,6 +25,7 @@ public abstract class BaseLocalhostClientTests private readonly string rootFilePath; private readonly string _mode; private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private readonly EventsManager _eventsManager; public BaseLocalhostClientTests(string mode) { @@ -31,6 +33,7 @@ public BaseLocalhostClientTests(string mode) rootFilePath = string.Empty; _mode = mode; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); + _eventsManager = new EventsManager(new EventsManagerConfig()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -42,7 +45,7 @@ public async Task GetTreatmentAsync() { // Arrange. var config = GetConfiguration($"{rootFilePath}test.splits"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -81,7 +84,7 @@ public void GetTreatmentSuccessfully() { //Arrange var config = GetConfiguration($"{rootFilePath}test.splits"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -105,7 +108,7 @@ public void GetTreatmentSuccessfullyWhenUpdatingSplitsFile() // Arrange var filePath = $"{rootFilePath}test2-{_mode}.splits"; var config = GetConfiguration(filePath); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -148,7 +151,7 @@ public void GetTreatmentSuccessfullyWhenUpdatingSplitsFileSameFile() Thread.Sleep(1000); var config = GetConfiguration(filePath); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -171,7 +174,7 @@ public void ClientDestroySuccessfully() { //Arrange var config = GetConfiguration($"{rootFilePath}test.splits"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -193,7 +196,7 @@ public void GetTreatment_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -225,7 +228,7 @@ public void GetTreatmentWithConfig_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -264,7 +267,7 @@ public void GetTreatment_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -296,7 +299,7 @@ public void GetTreatmentWithConfig_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -335,7 +338,7 @@ public void GetTreatments_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -372,7 +375,7 @@ public void GetTreatmentsWithConfig_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -423,7 +426,7 @@ public void GetTreatments_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -460,7 +463,7 @@ public void GetTreatmentsWithConfig_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator); + var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -514,7 +517,7 @@ public void FallbackTreatments_WhenFeatureDoesNotExist() FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, fallbackTreatmentCalculator); + var client = new LocalhostClient(config, fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); diff --git a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs index 5732ce6c..2279838c 100644 --- a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json.Serialization; using Splitio.Domain; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; namespace Splitio_Tests.Integration_Tests @@ -12,12 +13,14 @@ public class InMemoryClientTests { private readonly string rootFilePath; private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private readonly EventsManager _eventsManager; public InMemoryClientTests() { // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); + _eventsManager = new EventsManager(new EventsManagerConfig()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -36,7 +39,7 @@ public void OverridingJsonConvertSettingSnakeCaseNamingStrategy() NamingStrategy = new SnakeCaseNamingStrategy() } }; - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); //Act diff --git a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs index efc6e8b7..6bdc8e55 100644 --- a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs @@ -3,6 +3,7 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Events.Interfaces; using Splitio.Services.Impressions.Classes; using Splitio.Services.Impressions.Interfaces; @@ -19,12 +20,14 @@ public class JSONFileClientTests { private readonly string rootFilePath; private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private readonly EventsManager _eventsManager; public JSONFileClientTests() { // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); + _eventsManager = new EventsManager(new EventsManagerConfig()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -37,7 +40,7 @@ public JSONFileClientTests() public void ExecuteGetTreatmentOnFailedParsingSplitShouldReturnControl() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); //Act var result = client.GetTreatment("test", "fail", null); @@ -52,7 +55,7 @@ public void ExecuteGetTreatmentOnFailedParsingSplitShouldReturnControl() public void ExecuteGetTreatmentOnFailedParsingSplitShouldNotAffectOtherSplits() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -69,7 +72,7 @@ public void ExecuteGetTreatmentOnFailedParsingSplitShouldNotAffectOtherSplits() public void ExecuteGetTreatmentOnDeletedSplitShouldReturnControl() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -97,7 +100,7 @@ public void ExecuteGetTreatmentOnExceptionShouldReturnControl() .Setup(x => x.GetSplit(It.IsAny())) .Throws(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, null, splitCacheMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, null, splitCacheMock.Object); //Act var result = client.GetTreatment("test", "asd", null); @@ -113,7 +116,7 @@ public void ExecuteGetTreatmentOnExceptionShouldReturnControl() public void ExecuteGetTreatmentOnRemovedUserFromSegmentShouldReturnOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", $"{rootFilePath}segment_payed.json", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", $"{rootFilePath}segment_payed.json", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -135,7 +138,7 @@ public void ExecuteGetTreatmentOnRemovedUserFromSegmentShouldReturnOff() public void ExecuteGetTreatmentOnSplitWithOnOffOnPartition() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -159,7 +162,7 @@ public void ExecuteGetTreatmentOnSplitWithOnOffOnPartition() public void ExecuteGetTreatmentOnSplitWithTrafficAllocation() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -183,7 +186,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocation() public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIsDifferentThan100() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -207,7 +210,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIsDiffe public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1ReturnsRolloutTreatment() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -223,7 +226,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1Retu public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1ReturnsDefaultTreatment() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -239,7 +242,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1Retu public void ExecuteGetTreatmentOnSplitWithSegmentNotInitialized() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -259,7 +262,7 @@ public void ExecuteGetTreatmentAndLogLabelKilled() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -283,7 +286,7 @@ public void ExecuteGetTreatmentAndLogLabelNoConditionMatched() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -307,7 +310,7 @@ public void ExecuteGetTreatmentAndLogLabelSplitNotFound() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); //Act client.RemoveSplitFromCache("asd"); @@ -336,7 +339,7 @@ public void ExecuteGetTreatmentAndLogLabelException() .Setup(x => x.GetSplit(It.IsAny())) .Throws(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, featureFlagCacheInstance: splitCacheMock.Object, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, featureFlagCacheInstance: splitCacheMock.Object, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -360,7 +363,7 @@ public void ExecuteGetTreatmentAndLogLabelTrafficAllocationFailed() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -383,7 +386,7 @@ public void ExecuteGetTreatmentAndLogLabelForTreatment() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -406,7 +409,7 @@ public void ExecuteGetTreatmentAndLogLabelForTreatment() public void ExecuteGetTreatmentWhenUnknownMatcherIsIncluded() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); //Act var result = client.GetTreatment("xs", "Unknown_Matcher", null); @@ -421,7 +424,7 @@ public void ExecuteGetTreatmentAndNotLogLabelForTreatmentIfLabelsNotEnabled() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object, isLabelsEnabled: false); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object, isLabelsEnabled: false); client.BlockUntilReady(1000); @@ -444,7 +447,7 @@ public void ExecuteGetTreatmentAndLogLabelAndBucketingKeyForTreatment() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -468,7 +471,7 @@ public void ExecuteGetTreatmentAndLogLabelAndBucketingKeyForTreatment() public void ExecuteGetTreatmentWithBooleanAttribute() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); var attributes = new Dictionary { @@ -490,7 +493,7 @@ public void ExecuteGetTreatmentWithBooleanAttribute() public void ExecuteGetTreatmentWithSetMatcherReturnsOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); var attributes = new Dictionary { @@ -512,7 +515,7 @@ public void ExecuteGetTreatmentWithSetMatcherReturnsOff() public void ExecuteGetTreatmentWithSetMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); var attributes = new Dictionary { @@ -534,7 +537,7 @@ public void ExecuteGetTreatmentWithSetMatcherReturnsOn() public void ExecuteGetTreatmentWithStringMatcherReturnsOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); var attributes = new Dictionary { @@ -556,7 +559,7 @@ public void ExecuteGetTreatmentWithStringMatcherReturnsOff() public void ExecuteGetTreatmentWithStringMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); var attributes = new Dictionary { @@ -578,7 +581,7 @@ public void ExecuteGetTreatmentWithStringMatcherReturnsOn() public void ExecuteGetTreatmentWithDependencyMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -595,7 +598,7 @@ public void ExecuteGetTreatmentWithDependencyMatcherReturnsOn() public void ExecuteGetTreatmentWithDependencyMatcherReturnsOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -613,7 +616,7 @@ public void ExecuteGetTreatmentWithDependencyMatcherImpressionOnChild() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager,impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -631,7 +634,7 @@ public void GetTreatment_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); var splitName = "not_exist"; client.BlockUntilReady(1000); @@ -649,7 +652,7 @@ public void GetTreatment_WhenNameDoesntExist_DontLogImpression() public void GetTreatment_WithoutBlockUntiltReady_ReturnsOff() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatment("key", "anding"); @@ -665,7 +668,7 @@ public void GetTreatment_WithoutBlockUntiltReady_ReturnsOff() public void ExecuteGetTreatments() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); List features = new List { "fail", @@ -696,7 +699,7 @@ public void ExecuteGetTreatments() public void ExecuteGetTreatmentsWithBucketing() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); List features = new List { "fail", @@ -728,7 +731,7 @@ public void ExecuteGetTreatmentsWithBucketing() public void ExecuteGetTreatmentsWithDependencyMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -751,7 +754,7 @@ public void ExecuteGetTreatmentsWithDependencyMatcherReturnsOn() public void ExecuteGetTreatmentsWithDependencyMatcherWithAttributesReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(1000); @@ -779,7 +782,7 @@ public void GetTreatments_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); var splitNames = new List { "not_exist", "not_exist_1" }; client.BlockUntilReady(1000); @@ -801,7 +804,7 @@ public void GetTreatments_WhenNameDoesntExist_DontLogImpression() public void GetTreatments_WithoutBlockUntiltReady_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatments("key", new List()); @@ -815,7 +818,7 @@ public void GetTreatments_WithoutBlockUntiltReady_ReturnsEmptyList() public void GetTreatments_WithoutBlockUntiltReady_ReturnsTreatments() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatments("key", new List { "anding", "in_ten_keys" }); @@ -833,7 +836,7 @@ public void GetTreatments_WithoutBlockUntiltReady_ReturnsTreatments() public void GetTreatments_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(100); // Act. @@ -850,7 +853,7 @@ public void GetTreatments_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsEmptyList() public void DestroySucessfully() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); var attributes = new Dictionary { @@ -886,7 +889,7 @@ public void Track_WhenClientIsNotReady_ReturnsTrue() // Arrange. var trafficTypeValidator = new Mock(); var eventLog = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, trafficTypeValidator: trafficTypeValidator.Object, eventsLog: eventLog.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, trafficTypeValidator: trafficTypeValidator.Object, eventsLog: eventLog.Object); trafficTypeValidator .Setup(mock => mock.IsValid(It.IsAny(), It.IsAny())) @@ -907,7 +910,7 @@ public void GetTreatmentWithConfig_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); var splitName = "not_exist"; client.BlockUntilReady(1000); @@ -926,7 +929,7 @@ public void GetTreatmentWithConfig_WhenNameDoesntExist_DontLogImpression() public void GetTreatmentWithConfig_WithoutBlockUntiltReady_ReturnsOff() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatmentWithConfig("key", "anding"); @@ -944,7 +947,7 @@ public void GetTreatmentsWithConfig_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); var splitNames = new List { "not_exist", "not_exist_1" }; client.BlockUntilReady(1000); @@ -967,7 +970,7 @@ public void GetTreatmentsWithConfig_WhenNameDoesntExist_DontLogImpression() public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatmentsWithConfig("anding", new List()); @@ -981,7 +984,7 @@ public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsEmptyList() public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsTreatments() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatmentsWithConfig("key", new List { "anding", "whitelisting_elements" }); @@ -1001,7 +1004,7 @@ public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsTreatments() public void GetTreatmentsWithConfig_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(100); // Act. @@ -1018,7 +1021,7 @@ public void GetTreatmentsWithConfig_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsE public void Split_Manager_WhenNameDoesntExist_ReturnsNull() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); var manager = client.GetSplitManager(); var splitName = "not_exist"; diff --git a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs index 84ebcbd7..8ad5f8be 100644 --- a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs @@ -4,6 +4,7 @@ using Splitio.Redis.Services.Client.Classes; using Splitio.Redis.Services.Domain; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Tests.Common.Resources; using Splitio_Tests.Resources; @@ -25,6 +26,7 @@ public class RedisClientTests private ConfigurationOptions config; private RedisAdapterForTests _redisAdapter; private FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private EventsManager _eventsManager; [TestInitialize] public void Initialization() @@ -38,6 +40,7 @@ public void Initialization() UserPrefix = _prefix }; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); + _eventsManager = new EventsManager(new EventsManagerConfig()); config = new ConfigurationOptions { CacheAdapterConfig = cacheAdapterConfig, @@ -64,7 +67,7 @@ public void Initialization() public void GetTreatment_WhenFeatureExists_ReturnsOn() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); @@ -75,7 +78,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOn() Assert.IsNotNull(result); Assert.AreEqual("on", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); @@ -91,7 +94,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOn() public void GetTreatment_WhenFeatureExists_ReturnsOff() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); @@ -102,7 +105,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOff() Assert.IsNotNull(result); Assert.AreEqual("off", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatment("test", "always_off", null); @@ -116,7 +119,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOff() public void GetTreatment_WhenFeatureDoenstExist_ReturnsControl() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); //Act @@ -126,7 +129,7 @@ public void GetTreatment_WhenFeatureDoenstExist_ReturnsControl() Assert.IsNotNull(result); Assert.AreEqual("control", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatment("test", "always_control", null); @@ -145,7 +148,7 @@ public void GetTreatments_WhenFeaturesExists_ReturnsOnOff() var features = new List { alwaysOn, alwaysOff }; - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); @@ -159,7 +162,7 @@ public void GetTreatments_WhenFeaturesExists_ReturnsOnOff() var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), - API_KEY, _fallbackTreatmentCalculator); + API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatments("test", features, null); @@ -180,7 +183,7 @@ public void GetTreatments_WhenOneFeatureDoenstExist_ReturnsOnOffControl() var features = new List { alwaysOn, alwaysOff, alwaysControl }; - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); @@ -194,7 +197,7 @@ public void GetTreatments_WhenOneFeatureDoenstExist_ReturnsOnOffControl() Assert.AreEqual("control", result[alwaysControl]); var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), - API_KEY, _fallbackTreatmentCalculator); + API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatments("test", features, null); @@ -210,7 +213,7 @@ public void GetTreatments_WhenOneFeatureDoenstExist_ReturnsOnOffControl() public void GetTreatmentsWithConfig_WhenClientIsNotReady_ReturnsControl() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatmentsWithConfig("key", new List()); @@ -223,7 +226,7 @@ public void GetTreatmentsWithConfig_WhenClientIsNotReady_ReturnsControl() } var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator); +API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatmentsWithConfig("key", new List()); @@ -240,7 +243,7 @@ public void GetTreatmentsWithConfig_WhenClientIsNotReady_ReturnsControl() public void GetTreatmentWithConfig_WhenClientIsNotReady_ReturnsControl() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatmentWithConfig("key", string.Empty); @@ -250,7 +253,7 @@ public void GetTreatmentWithConfig_WhenClientIsNotReady_ReturnsControl() Assert.IsNull(result.Config); var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator); +API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatmentWithConfig("key", string.Empty); @@ -264,7 +267,7 @@ public void GetTreatmentWithConfig_WhenClientIsNotReady_ReturnsControl() public void GetTreatment_WhenClientIsNotReady_ReturnsControl() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatment("key", string.Empty); @@ -273,7 +276,7 @@ public void GetTreatment_WhenClientIsNotReady_ReturnsControl() Assert.AreEqual("control", result); var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator); +API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatment("key", string.Empty); @@ -287,7 +290,7 @@ public void GetTreatments_WhenClientIsNotReady_ReturnsControl() { // Arrange. config.CacheAdapterConfig.Host = "fake-host"; - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.GetTreatments("key", new List()); @@ -298,7 +301,7 @@ public void GetTreatments_WhenClientIsNotReady_ReturnsControl() Assert.AreEqual("control", res.Value); } - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); result = client2.GetTreatments("key", new List()); @@ -314,7 +317,7 @@ public void GetTreatments_WhenClientIsNotReady_ReturnsControl() public void Track_WhenClientIsNotReady_ReturnsTrue() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); // Act. var result = client.Track("key", "traffic_type", "event_type"); @@ -323,7 +326,7 @@ public void Track_WhenClientIsNotReady_ReturnsTrue() Assert.IsTrue(result); var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator); +API_KEY, _fallbackTreatmentCalculator, _eventsManager); client2.BlockUntilReady(5000); // Act. @@ -342,7 +345,7 @@ public void FallbackTreatments_WhenFeatureDoesNotExist() FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); - var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); @@ -380,7 +383,7 @@ public void FallbackTreatments_WhenClientNotReady() FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); config.CacheAdapterConfig.Host = "fake-host"; - var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator, _eventsManager); //Act var result = client.GetTreatmentsWithConfig("test", features, null); @@ -402,7 +405,7 @@ public void FallbackTreatments_WhenExceptionOccurrs() FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); - var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); @@ -431,7 +434,7 @@ public void FallbackTreatments_WhenExceptionOccurrs() public void Destroy() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator); + var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); client.BlockUntilReady(5000); //Act diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index f2b7dfe7..e6049299 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -46,7 +46,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(eventsManager); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -92,7 +92,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAll var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging_4.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(eventsManager); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -141,8 +141,8 @@ public async Task ExecuteGetWithoutResults() var apiSplitChangeFetcher = new ApiSplitChangeFetcher(sdkApiClient); var sdkSegmentApiClient = new SegmentSdkApiClient(httpClient, telemetryStorage, baseUrl); var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); - var gates = new InMemoryReadinessGatesCache(); var eventsManager = new EventsManager(new EventsManagerConfig()); + var gates = new InMemoryReadinessGatesCache(eventsManager); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs index 09c6b39e..b97cff0e 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs @@ -1,11 +1,13 @@ -using Splitio.Services.Client.Classes; +using Splitio.Domain; +using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; namespace Splitio_Tests.Unit_Tests.Client { public class LocalhostClientForTesting : LocalhostClient { - public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator) + public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig())) { } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs index aaf4a6a2..95ecd3ba 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs @@ -1,6 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Shared.Classes; @@ -11,12 +12,14 @@ public class LocalhostClientUnitTests { private readonly string rootFilePath; private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private readonly EventsManager _eventsManager; public LocalhostClientUnitTests() { // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); + _eventsManager = new EventsManager(new EventsManagerConfig()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -28,7 +31,7 @@ public LocalhostClientUnitTests() public void GetTreatmentShouldReturnControlIfSplitNotFound() { //Arrange - var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }, _fallbackTreatmentCalculator); + var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }, _fallbackTreatmentCalculator, _eventsManager); //Act var result = splitClient.GetTreatment("test", "test"); @@ -41,7 +44,7 @@ public void GetTreatmentShouldReturnControlIfSplitNotFound() [DeploymentItem(@"Resources\test.splits")] public void GetTreatmentShouldRunAsSingleKeyUsingNullBucketingKey() { - var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }, _fallbackTreatmentCalculator); + var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }, _fallbackTreatmentCalculator, _eventsManager); splitClient.BlockUntilReady(1000); //Act diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index bf1e7b1b..83ca9c24 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -1,16 +1,23 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Splitio.Domain; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; +using System; namespace Splitio_Tests.Unit_Tests.Client { [TestClass] public class InMemoryReadinessGatesCacheUnitTests { + private bool SdkReady = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; + [TestMethod] public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() { //Arrange - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); //Act var result = gates.IsReady(); @@ -18,5 +25,29 @@ public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() //Assert Assert.IsFalse(result); } + + [TestMethod] + public void TestFireReadyEvent() + { + //Arrange + EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); + var gates = new InMemoryReadinessGatesCache(eventsManager); + PublicSdkUpdateHandler += sdkReady_callback; + eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + + //Act + gates.SetReady(); + + // Assert. + Assert.IsTrue(SdkReady); + Assert.AreEqual(0, eMetadata.GetData().Count); + } + + private void sdkReady_callback(object sender, EventMetadata metadata) + { + SdkReady = true; + eMetadata = metadata; + } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs index 80587cd2..12277bcb 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs @@ -1,4 +1,5 @@ -using Splitio.Services.Cache.Interfaces; +using Splitio.Domain; +using Splitio.Services.Cache.Interfaces; using Splitio.Services.Client.Classes; using Splitio.Services.Common; using Splitio.Services.Evaluator; @@ -22,7 +23,7 @@ public SplitClientForTesting(IFeatureFlagCacheConsumer featureFlagCacheConsumer, ISyncManager syncManager, FallbackTreatmentCalculator fallbackTreatmentCalculator, ITelemetryEvaluationProducer telemetryEvaluationProducer) - : base("SplitClientForTesting", fallbackTreatmentCalculator) + : base("SplitClientForTesting", fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig())) { _eventsLog = eventsLog; _impressionsLog = impressionsLog; diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index 77ce67e3..42df730c 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -1,6 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Splitio.Domain; using Splitio.Services.Client.Classes; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Impressions.Interfaces; using Splitio.Services.Tasks; @@ -27,7 +29,7 @@ public void Start_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -51,7 +53,7 @@ public void Start_ShouldNotSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -70,7 +72,7 @@ public async Task Stop_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -94,7 +96,7 @@ public async Task Stop_ShouldSendImpressionsCount() public async Task ShouldSend2BulksOfImpressions() { var config = new ComponentConfig(6, 3); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 9e242cc8..97a68959 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -27,7 +27,7 @@ public class SelfRefreshingSegmentFetcherUnitTests public void InitializeSegmentNotExistent() { // Arrange - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); gates.SetReady(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs new file mode 100644 index 00000000..d5204d8e --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -0,0 +1,52 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Splitio.Domain; +using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Common; +using Splitio.Services.Shared.Classes; +using Splitio.Telemetry.Storages; +using System; + +namespace Splitio_Tests.Unit_Tests.Shared +{ + [TestClass] + public class SelfRefreshingBlockUntilReadyServiceTests + { + private bool SdkTimedOut = false; + private EventMetadata eMetadata = null; + public event EventHandler PublicSdkUpdateHandler; + + [TestMethod] + public void TestFireTimedOutEvent() + { + //Arrange + Mock statusManager = new Mock(); + Mock telemetryProducer = new Mock(); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); + var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, eventsManager); + PublicSdkUpdateHandler += SdkTimedOut_callback; + eventsManager.Register(SdkEvent.SdkReadyTimeout, SdkTimedOut_callback); + statusManager + .Setup(mock => mock.WaitUntilReady(1)) + .Returns(false); + + //Act + try + { + bur.BlockUntilReady(1); + } + catch { } + + // Assert. + Assert.IsTrue(SdkTimedOut); + Assert.AreEqual(0, eMetadata.GetData().Count); + } + + private void SdkTimedOut_callback(object sender, EventMetadata metadata) + { + SdkTimedOut = true; + eMetadata = metadata; + } + } +} diff --git a/tests/Splitio.Integration-tests/EventSourceClientTests.cs b/tests/Splitio.Integration-tests/EventSourceClientTests.cs index ba776643..0eb26bdd 100644 --- a/tests/Splitio.Integration-tests/EventSourceClientTests.cs +++ b/tests/Splitio.Integration-tests/EventSourceClientTests.cs @@ -370,7 +370,7 @@ private static (IEventSourceClient, BlockingCollection, var sseHttpClient = new SplitioHttpClient("api-key", config, new Dictionary()); var telemetryRuntimeProducer = new InMemoryTelemetryStorage(); var notificationManagerKeeper = new NotificationManagerKeeper(telemetryRuntimeProducer, streamingStatusQueue); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); var tasksManager = new TasksManager(statusManager); var task = tasksManager.NewOnTimeTask(Enums.Task.SSEConnect); diff --git a/tests/Splitio.TestSupport/SplitClientForTest.cs b/tests/Splitio.TestSupport/SplitClientForTest.cs index ddffe2eb..f79f6674 100644 --- a/tests/Splitio.TestSupport/SplitClientForTest.cs +++ b/tests/Splitio.TestSupport/SplitClientForTest.cs @@ -1,4 +1,5 @@ using Splitio.Domain; +using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using System.Collections.Generic; using System.Threading.Tasks; @@ -9,7 +10,8 @@ public class SplitClientForTest : SplitClient { private readonly Dictionary _tests; - public SplitClientForTest() : base("SplitClientForTest", new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration())) + public SplitClientForTest() : base("SplitClientForTest", new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()), + new EventsManager(new EventsManagerConfig())) { _tests = new Dictionary(); } From 435f395dbbe8a5324ab74a19c2d3ebeb1d1016c8 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 18 Dec 2025 12:49:22 -0800 Subject: [PATCH 38/87] polish --- src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index ce314289..4cd7c08a 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -52,7 +52,7 @@ public class SelfRefreshingClient : SplitClient private IRuleBasedSegmentCache _ruleBasedSegmentCache; private IUpdater _ruleBasedSegmentUpdater; private readonly new FallbackTreatmentCalculator _fallbackTreatmentCalculator; - private EventsManager _eventsManager; + private readonly EventsManager _eventsManager; public SelfRefreshingClient(string apiKey, ConfigurationOptions config, FallbackTreatmentCalculator fallbackTreatmentCalculator, From b6d8a66ed9702817dcc85a7362c7e8fe893ac7a0 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 22 Dec 2025 08:45:39 -0800 Subject: [PATCH 39/87] Update src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 2517fc69..555d10f4 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -15,7 +15,7 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache private readonly EventsManager _eventsManager; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, - EventsManager eventsManger, + IEventsManager eventsManger, long changeNumber = -1) { _cache = cache; From 376b7adea1aacc048a23fd3ba6b2ce02417ace98 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 22 Dec 2025 08:45:45 -0800 Subject: [PATCH 40/87] Update src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 555d10f4..e6410984 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -12,7 +12,7 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache { private readonly ConcurrentDictionary _cache; private long _changeNumber; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, IEventsManager eventsManger, From 00f0868edf83df9c857a5b1e29c7b3f6d0af1190 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 22 Dec 2025 08:45:55 -0800 Subject: [PATCH 41/87] Update src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 7655a6e6..10ec56c0 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -15,7 +15,7 @@ public class InMemorySegmentCache : ISegmentCache private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemorySegmentCache)); private readonly ConcurrentDictionary _segments; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; public InMemorySegmentCache(ConcurrentDictionary segments, EventsManager eventsManger) { From 5bd554e28536fa805df55252ef9e57f833bb5615 Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Mon, 22 Dec 2025 08:46:03 -0800 Subject: [PATCH 42/87] Update src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 10ec56c0..cf00d483 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -17,7 +17,7 @@ public class InMemorySegmentCache : ISegmentCache private readonly ConcurrentDictionary _segments; private readonly IEventsManager _eventsManager; - public InMemorySegmentCache(ConcurrentDictionary segments, EventsManager eventsManger) + public InMemorySegmentCache(ConcurrentDictionary segments, IEventsManager eventsManger) { _segments = segments; _eventsManager = eventsManger; From 9c32ca03ebe9aa01d01dfed1267486a61e99501b Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 08:53:19 -0800 Subject: [PATCH 43/87] Added notify when removing rbsegment --- .../Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 6 ++++-- src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index e6410984..1789b8e9 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -2,6 +2,7 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; +using Splitio.Services.SegmentFetcher.Interfaces; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -12,10 +13,10 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache { private readonly ConcurrentDictionary _cache; private long _changeNumber; - private readonly IEventsManager _eventsManager; + private readonly EventsManager _eventsManager; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, - IEventsManager eventsManger, + EventsManager eventsManger, long changeNumber = -1) { _cache = cache; @@ -60,6 +61,7 @@ public void Update(List toAdd, List toRemove, long til foreach (var name in toRemove) { _cache.TryRemove(name, out var _); + toNotify.Add(name); } SetChangeNumber(till); diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index cf00d483..7655a6e6 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -15,9 +15,9 @@ public class InMemorySegmentCache : ISegmentCache private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemorySegmentCache)); private readonly ConcurrentDictionary _segments; - private readonly IEventsManager _eventsManager; + private readonly EventsManager _eventsManager; - public InMemorySegmentCache(ConcurrentDictionary segments, IEventsManager eventsManger) + public InMemorySegmentCache(ConcurrentDictionary segments, EventsManager eventsManger) { _segments = segments; _eventsManager = eventsManger; From 492d2e2d84d17ae69569a31228af18059945bd4d Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 09:43:44 -0800 Subject: [PATCH 44/87] fixed test --- .../Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index e3ba2df2..eddab8b7 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -159,7 +159,7 @@ public void Update_ShouldNotifyEvent() var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; - var toNotify = new List { { "segment-to-add" } }; + var toNotify = new List { { "segment-to-add" }, { "segment-to-remove" } }; PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); @@ -174,7 +174,7 @@ public void Update_ShouldNotifyEvent() Assert.IsTrue(SdkUpdate); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; - Assert.IsTrue(rbsegments.Count == 2); + Assert.IsTrue(rbsegments.Count == 3); Assert.IsTrue(rbsegments.Contains("segment-to-add")); Assert.IsTrue(rbsegments.Contains("segment-to-remove")); } From 015310e6cf4e0e1b1691fccdec9d198394a5ace5 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 14:44:40 -0800 Subject: [PATCH 45/87] moved helper fucntions to events manager class --- .../Classes/InMemoryRuleBasedSegmentCache.cs | 5 +- .../Cache/Classes/InMemorySegmentCache.cs | 8 +- .../Cache/Classes/InMemorySplitCache.cs | 8 +- .../Services/Client/Classes/SplitClient.cs | 3 + src/Splitio/Services/Common/EventDelivery.cs | 2 +- src/Splitio/Services/Common/EventsManager.cs | 142 ++++++++++++++++- src/Splitio/Services/Common/IEventsManager.cs | 2 +- src/Splitio/Util/Helper.cs | 146 ------------------ .../InMemory/RuleBasedSegmentCacheTests.cs | 4 +- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 5 +- .../Cache/InMemory/SegmentCacheTests.cs | 4 +- .../Cache/InMemory/SplitCacheAsyncTests.cs | 4 +- .../Cache/InMemory/SplitCacheTests.cs | 4 +- .../Unit Tests/Common/EventsManagerTests.cs | 75 ++++----- 14 files changed, 180 insertions(+), 232 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 1789b8e9..30c1fbc9 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -2,7 +2,6 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; -using Splitio.Services.SegmentFetcher.Interfaces; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -66,9 +65,7 @@ public void Update(List toAdd, List toRemove, long til SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.RuleBasedSegments, toNotify } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.RuleBasedSegments, toNotify } })); } public void SetChangeNumber(long changeNumber) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 7655a6e6..c0b5d8a5 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -36,9 +36,7 @@ public void AddToSegment(string segmentName, List segmentKeys) segment.AddKeys(segmentKeys); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } })); } public void RemoveFromSegment(string segmentName, List segmentKeys) @@ -47,9 +45,7 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) { segment.RemoveKeys(segmentKeys); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } })); } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index bd3f53c0..d222aa12 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -79,9 +79,7 @@ public void Update(List toAdd, List toRemove, long till) SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, eventsFlags } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, eventsFlags } })); } public void SetChangeNumber(long changeNumber) @@ -154,9 +152,7 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, - new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, new List { { featureFlag.name } } } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, new List { { featureFlag.name } } } })); } diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 54297fdf..4372c344 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,6 +63,9 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; + public event EventHandler PublicSdkReadyHandler; + public event EventHandler PublicSdkUpdateHandler; + public event EventHandler PublicSdkTimedOutHandler; protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator) { diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index be28dd36..b97e7a32 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -15,7 +15,7 @@ public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { - handler(this, eventMetadata); + handler.Invoke(this, eventMetadata); } catch (Exception e) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index acb23688..79ad8373 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -4,11 +4,18 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; namespace Splitio.Services.Common { public class EventsManager : IEventsManager { + public struct ValidSdkEvent + { + public E SdkEvent { get; set; } + public bool Valid { get; set; } + } + private struct PublicEventProperties { public bool Triggered; @@ -19,14 +26,14 @@ private struct PublicEventProperties private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); private readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); - public EventsManagerConfig ManagerConfig { get; private set; } + public EventManagerConfigData _managerConfig { get; private set; } - public EventsManager(EventsManagerConfig eventsManagerConfig) + public EventsManager(EventManagerConfigData eventsManagerConfig) { _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); _eventDelivery = new EventDelivery(); - ManagerConfig = eventsManagerConfig; + _managerConfig = eventsManagerConfig; } #region Public Methods @@ -53,13 +60,13 @@ public void Unregister(E sdkEvent) } } - public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eventsToNotify) + public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata) { lock (_lock) { _logger.Debug($"EventsManager: Handling internal event {sdkInternalEvent}"); - foreach (E sdkEvent in eventsToNotify) + foreach (E sdkEvent in GetSdkEventIfApplicable(sdkInternalEvent)) { _logger.Debug($"EventsManager: Firing Sdk event {sdkEvent}"); _eventDelivery.Deliver(sdkEvent, eventMetadata, GetEventHandler(sdkEvent)); @@ -118,6 +125,131 @@ private EventHandler GetEventHandler(E sdkEvent) return eventData.EventHandler; } + + public List GetSdkEventIfApplicable(I sdkInternalEvent) + { + ValidSdkEvent finalSdkEvent = new ValidSdkEvent + { + Valid = false +// SdkEvent = SdkEvent.SdkReady + }; + UpdateSdkInternalEventStatus(sdkInternalEvent, true); + List eventsToFire = new List(); + + ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); + if (requireAnySdkEvent.Valid) + { + if ((!EventAlreadyTriggered(requireAnySdkEvent.SdkEvent) + && ExecutionLimit(requireAnySdkEvent.SdkEvent) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent) == -1) + { + finalSdkEvent.SdkEvent = requireAnySdkEvent.SdkEvent; + } + + finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent) + && CheckSuppressedBy(finalSdkEvent.SdkEvent); + } + + if (finalSdkEvent.Valid) + { + eventsToFire.Add(finalSdkEvent.SdkEvent); + } + + foreach (E sdkEvent in CheckRequireAll()) + { + eventsToFire.Add(sdkEvent); + } + + return eventsToFire; + } + + private List CheckRequireAll() + { + List events = new List(); + foreach (KeyValuePair> kvp in _managerConfig.RequireAll) + { + bool finalStatus = true; + foreach (var val in kvp.Value) + { + finalStatus &= GetSdkInternalEventStatus(val); + } + if (finalStatus + && CheckPrerequisites(kvp.Key) + && ((ExecutionLimit(kvp.Key) == 1 && !EventAlreadyTriggered(kvp.Key)) + || (ExecutionLimit(kvp.Key) == -1)) + && kvp.Value.Count > 0) + { + events.Add(kvp.Key); + } + } + + return events; + } + + private bool CheckPrerequisites(E sdkEvent) + { + foreach (KeyValuePair> kvp in _managerConfig.Prerequisites) + { + if (kvp.Key.Equals(sdkEvent)) + { + if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + + private bool CheckSuppressedBy(E sdkEvent) + { + foreach (KeyValuePair> kvp in _managerConfig.SuppressedBy) + { + if (kvp.Key.Equals(sdkEvent)) + { + if (kvp.Value.Any(x => EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + + private int ExecutionLimit(E sdkEvent) + { + if (!_managerConfig.ExecutionLimits.ContainsKey(sdkEvent)) + return -1; + + _managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); + return limit; + } + + private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) + { + ValidSdkEvent validSdkEvent = new ValidSdkEvent + { + Valid = false +// SdkEvent = SdkEvent.SdkUpdate + }; + + foreach (KeyValuePair> kvp in _managerConfig.RequireAny) + { + if (kvp.Value.Contains(sdkInternalEvent)) + { + validSdkEvent.Valid = true; + validSdkEvent.SdkEvent = kvp.Key; + return validSdkEvent; + } + } + + return validSdkEvent; + } #endregion } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index fd606b1a..23e719c7 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -6,7 +6,7 @@ namespace Splitio.Services.Common { public interface IEventsManager { - void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eventsToNotify); + void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata); void Register(E sdkEvent, EventHandler handler); void Unregister(E sdkEvent); } diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index c9854f23..84dc8dda 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -1,6 +1,5 @@ using Splitio.CommonLibraries; using Splitio.Domain; -using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Logger; using Splitio.Telemetry.Domain.Enums; @@ -12,12 +11,6 @@ namespace Splitio.Util { public class Helper { - public struct ValidSdkEvent - { - public SdkEvent SdkEvent { get; set; } - public bool Valid { get; set; } - } - public static List TakeFromList(List items, int size) { if (items == null) return new List(); @@ -91,144 +84,5 @@ public static string getFallbackConfig(FallbackTreatment fallbackTreatment) return null; } - - public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent, - EventsManager eventsManager) - { - ValidSdkEvent finalSdkEvent = new ValidSdkEvent - { - Valid = false, - SdkEvent = SdkEvent.SdkReady - }; - eventsManager.UpdateSdkInternalEventStatus(sdkInternalEvent, true); - List eventsToFire = new List(); - - ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent, eventsManager.ManagerConfig); - if (requireAnySdkEvent.Valid) - { - if ((!eventsManager.EventAlreadyTriggered(requireAnySdkEvent.SdkEvent) - && ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManager.ManagerConfig) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManager.ManagerConfig) == -1) - { - finalSdkEvent.SdkEvent = requireAnySdkEvent.SdkEvent; - } - - finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent, eventsManager) - && CheckSuppressedBy(finalSdkEvent.SdkEvent, eventsManager); - } - - if (finalSdkEvent.Valid) - { - eventsToFire.Add(finalSdkEvent.SdkEvent); - } - - foreach (SdkEvent sdkEvent in CheckRequireAll(eventsManager)) - { - eventsToFire.Add(sdkEvent); - } - - return eventsToFire; - } - - private static List CheckRequireAll( - EventsManager eventsManager) - { - List events = new List(); - foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.RequireAll) - { - bool finalStatus = true; - foreach (var val in kvp.Value) - { - finalStatus &= eventsManager.GetSdkInternalEventStatus(val); - } - if (finalStatus - && CheckPrerequisites(kvp.Key, eventsManager) - && ((ExecutionLimit(kvp.Key, eventsManager.ManagerConfig) == 1 && !eventsManager.EventAlreadyTriggered(kvp.Key)) - || (ExecutionLimit(kvp.Key, eventsManager.ManagerConfig) == -1)) - && kvp.Value.Count > 0) - { - events.Add(kvp.Key); - } - } - - return events; - } - - private static bool CheckPrerequisites(SdkEvent sdkEvent, - EventsManager eventsManager) - { - foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.Prerequisites) - { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => !eventsManager.EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } - } - - return true; - } - - private static bool CheckSuppressedBy(SdkEvent sdkEvent, - EventsManager eventsManager) - { - foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.SuppressedBy) - { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => eventsManager.EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } - } - - return true; - } - - private static int ExecutionLimit(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig) - { - if (!eventsManagerConfig.ExecutionLimits.ContainsKey(sdkEvent)) - return -1; - - eventsManagerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); - return limit; - } - - private static ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent, EventsManagerConfig eventsManagerConfig) - { - ValidSdkEvent validSdkEvent = new ValidSdkEvent - { - Valid = false, - SdkEvent = SdkEvent.SdkUpdate - }; - - foreach (KeyValuePair> kvp in eventsManagerConfig.RequireAny) - { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = kvp.Key; - return validSdkEvent; - } - } - - return validSdkEvent; - } - - public static void BuildInternalSdkEventStatus(EventsManager eventsManager) - { - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, false); - } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index eddab8b7..d4f207c5 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -154,7 +154,6 @@ public void Contains_ShouldReturnTrue() public void Update_ShouldNotifyEvent() { // Arrange - Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; @@ -163,8 +162,7 @@ public void Update_ShouldNotifyEvent() PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index 806d67b2..d44a7343 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -7,7 +7,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; -using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Cache { @@ -60,13 +59,11 @@ public async Task NotifyEventsTest() { //Arrange var segmentName = "segment_test"; - Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); var toNotify = new List { { segmentName } }; PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); //Act SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index b81611a4..fd9bac22 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -105,7 +105,6 @@ public void NotifyEventsTest() { //Arrange var eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; @@ -113,8 +112,7 @@ public void NotifyEventsTest() PublicSdkUpdateHandler += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 5d3b4c18..9fb65e65 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -27,7 +27,6 @@ public SplitCacheAsyncTests() _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); _eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); } @@ -197,8 +196,7 @@ public async Task NotifyUpdateEventTest() PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); SdkUpdate = false; _cache.Update(toAdd, new List(), -1); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 35a59f45..3d545067 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -245,7 +245,6 @@ public void NotifyUpdateEventTest() { // Arrange. var eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; @@ -253,8 +252,7 @@ public void NotifyUpdateEventTest() PublicSdkUpdateHandler += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act. SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 558fa68c..3c1a25d9 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -10,6 +10,7 @@ namespace Splitio_Tests.Unit_Tests.Common public class EventsManagerTests { private bool SdkReady = false; + private bool SdkReady2 = false; private bool SdkTimedOut = false; private bool SdkUpdate = false; private EventMetadata eMetadata = null; @@ -23,49 +24,36 @@ public void TestFiringEvents() //Act EventsManagerConfig config = new EventsManagerConfig(); EventsManager eventsManager = new EventsManager(config); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); PublicSdkReadyHandler += sdkReady_callback; + PublicSdkReadyHandler += sdkReady_callback2; PublicSdkUpdateHandler += sdkUpdate_callback; PublicSdkTimedOutHandler += sdkTimedOut_callback; - Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - eventsManager)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - eventsManager)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - eventsManager)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - eventsManager)); + eventsManager.Register(SdkEvent.SdkReady, PublicSdkReadyHandler); + eventsManager.Register(SdkEvent.SdkUpdate, PublicSdkUpdateHandler); + + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet - eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - eventsManager)); + eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); @@ -73,30 +61,24 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - List eventsToNotify = Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, - eventsManager); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData), - eventsToNotify); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); + Assert.IsTrue(SdkReady2); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - eventsManager)); + eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -104,9 +86,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -114,9 +94,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -124,9 +102,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -136,9 +112,7 @@ public void TestFiringEvents() eventsManager.Unregister(SdkEvent.SdkUpdate); eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -148,6 +122,7 @@ public void TestFiringEvents() void ResetAllVariables() { SdkReady = false; + SdkReady2 = false; SdkTimedOut = false; eMetadata = null; SdkUpdate = false; @@ -173,6 +148,12 @@ private void sdkReady_callback(object sender, EventMetadata metadata) eMetadata = metadata; } + private void sdkReady_callback2(object sender, EventMetadata metadata) + { + SdkReady2 = true; + eMetadata = metadata; + } + private void sdkTimedOut_callback(object sender, EventMetadata metadata) { SdkTimedOut = true; From 9621a2650e22f962051a561297214b4c6cb41905 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 15:17:58 -0800 Subject: [PATCH 46/87] applied event manager changes --- .../Classes/InMemoryReadinessGatesCache.cs | 4 +- .../Classes/InMemoryRuleBasedSegmentCache.cs | 5 +- .../Cache/Classes/InMemorySegmentCache.cs | 8 +- .../Cache/Classes/InMemorySplitCache.cs | 8 +- .../Services/Client/Classes/SplitClient.cs | 6 +- src/Splitio/Services/Common/EventDelivery.cs | 2 +- src/Splitio/Services/Common/EventsManager.cs | 142 ++++++++++++++++- src/Splitio/Services/Common/IEventsManager.cs | 2 +- .../SelfRefreshingBlockUntilReadyService.cs | 4 +- src/Splitio/Util/Helper.cs | 146 ------------------ .../InMemory/RuleBasedSegmentCacheTests.cs | 8 +- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 5 +- .../Cache/InMemory/SegmentCacheTests.cs | 4 +- .../Cache/InMemory/SplitCacheAsyncTests.cs | 4 +- .../Cache/InMemory/SplitCacheTests.cs | 4 +- .../Client/LocalhostClientUnitTests.cs | 6 +- .../Client/SdkReadinessGatesUnitTests.cs | 3 +- .../Unit Tests/Common/EventsManagerTests.cs | 75 ++++----- ...lfRefreshingBlockUntilReadyServiceTests.cs | 3 +- 19 files changed, 193 insertions(+), 246 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index d3121456..d0a7d441 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -31,9 +31,7 @@ public void SetReady() { _sdkReady.Signal(); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, - new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, - _eventsManager)); + new EventMetadata(new Dictionary())); } public void SetDestroy() diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 2517fc69..30c1fbc9 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -60,13 +60,12 @@ public void Update(List toAdd, List toRemove, long til foreach (var name in toRemove) { _cache.TryRemove(name, out var _); + toNotify.Add(name); } SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.RuleBasedSegments, toNotify } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.RuleBasedSegments, toNotify } })); } public void SetChangeNumber(long changeNumber) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 7655a6e6..c0b5d8a5 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -36,9 +36,7 @@ public void AddToSegment(string segmentName, List segmentKeys) segment.AddKeys(segmentKeys); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } })); } public void RemoveFromSegment(string segmentName, List segmentKeys) @@ -47,9 +45,7 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) { segment.RemoveKeys(segmentKeys); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } })); } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index bd3f53c0..d222aa12 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -79,9 +79,7 @@ public void Update(List toAdd, List toRemove, long till) SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, eventsFlags } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, eventsFlags } })); } public void SetChangeNumber(long changeNumber) @@ -154,9 +152,7 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, - new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, new List { { featureFlag.name } } } }), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - _eventsManager)); + new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, new List { { featureFlag.name } } } })); } diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 7f9c0fb0..e9c60ef6 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,12 +63,16 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; + protected EventsManager _eventsManager; + public event EventHandler PublicSdkReadyHandler; + public event EventHandler PublicSdkUpdateHandler; + public event EventHandler PublicSdkTimedOutHandler; protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, EventsManager eventsManager) { ApiKey = apikey; - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); + _eventsManager = eventsManager; _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _wrapperAdapter = WrapperAdapter.Instance(); diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index be28dd36..b97e7a32 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -15,7 +15,7 @@ public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { - handler(this, eventMetadata); + handler.Invoke(this, eventMetadata); } catch (Exception e) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index acb23688..79ad8373 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -4,11 +4,18 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Linq; namespace Splitio.Services.Common { public class EventsManager : IEventsManager { + public struct ValidSdkEvent + { + public E SdkEvent { get; set; } + public bool Valid { get; set; } + } + private struct PublicEventProperties { public bool Triggered; @@ -19,14 +26,14 @@ private struct PublicEventProperties private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); private readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); - public EventsManagerConfig ManagerConfig { get; private set; } + public EventManagerConfigData _managerConfig { get; private set; } - public EventsManager(EventsManagerConfig eventsManagerConfig) + public EventsManager(EventManagerConfigData eventsManagerConfig) { _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); _eventDelivery = new EventDelivery(); - ManagerConfig = eventsManagerConfig; + _managerConfig = eventsManagerConfig; } #region Public Methods @@ -53,13 +60,13 @@ public void Unregister(E sdkEvent) } } - public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eventsToNotify) + public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata) { lock (_lock) { _logger.Debug($"EventsManager: Handling internal event {sdkInternalEvent}"); - foreach (E sdkEvent in eventsToNotify) + foreach (E sdkEvent in GetSdkEventIfApplicable(sdkInternalEvent)) { _logger.Debug($"EventsManager: Firing Sdk event {sdkEvent}"); _eventDelivery.Deliver(sdkEvent, eventMetadata, GetEventHandler(sdkEvent)); @@ -118,6 +125,131 @@ private EventHandler GetEventHandler(E sdkEvent) return eventData.EventHandler; } + + public List GetSdkEventIfApplicable(I sdkInternalEvent) + { + ValidSdkEvent finalSdkEvent = new ValidSdkEvent + { + Valid = false +// SdkEvent = SdkEvent.SdkReady + }; + UpdateSdkInternalEventStatus(sdkInternalEvent, true); + List eventsToFire = new List(); + + ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent); + if (requireAnySdkEvent.Valid) + { + if ((!EventAlreadyTriggered(requireAnySdkEvent.SdkEvent) + && ExecutionLimit(requireAnySdkEvent.SdkEvent) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent) == -1) + { + finalSdkEvent.SdkEvent = requireAnySdkEvent.SdkEvent; + } + + finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent) + && CheckSuppressedBy(finalSdkEvent.SdkEvent); + } + + if (finalSdkEvent.Valid) + { + eventsToFire.Add(finalSdkEvent.SdkEvent); + } + + foreach (E sdkEvent in CheckRequireAll()) + { + eventsToFire.Add(sdkEvent); + } + + return eventsToFire; + } + + private List CheckRequireAll() + { + List events = new List(); + foreach (KeyValuePair> kvp in _managerConfig.RequireAll) + { + bool finalStatus = true; + foreach (var val in kvp.Value) + { + finalStatus &= GetSdkInternalEventStatus(val); + } + if (finalStatus + && CheckPrerequisites(kvp.Key) + && ((ExecutionLimit(kvp.Key) == 1 && !EventAlreadyTriggered(kvp.Key)) + || (ExecutionLimit(kvp.Key) == -1)) + && kvp.Value.Count > 0) + { + events.Add(kvp.Key); + } + } + + return events; + } + + private bool CheckPrerequisites(E sdkEvent) + { + foreach (KeyValuePair> kvp in _managerConfig.Prerequisites) + { + if (kvp.Key.Equals(sdkEvent)) + { + if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + + private bool CheckSuppressedBy(E sdkEvent) + { + foreach (KeyValuePair> kvp in _managerConfig.SuppressedBy) + { + if (kvp.Key.Equals(sdkEvent)) + { + if (kvp.Value.Any(x => EventAlreadyTriggered(x))) + { + return false; + } + + return true; + } + } + + return true; + } + + private int ExecutionLimit(E sdkEvent) + { + if (!_managerConfig.ExecutionLimits.ContainsKey(sdkEvent)) + return -1; + + _managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); + return limit; + } + + private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) + { + ValidSdkEvent validSdkEvent = new ValidSdkEvent + { + Valid = false +// SdkEvent = SdkEvent.SdkUpdate + }; + + foreach (KeyValuePair> kvp in _managerConfig.RequireAny) + { + if (kvp.Value.Contains(sdkInternalEvent)) + { + validSdkEvent.Valid = true; + validSdkEvent.SdkEvent = kvp.Key; + return validSdkEvent; + } + } + + return validSdkEvent; + } #endregion } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index fd606b1a..23e719c7 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -6,7 +6,7 @@ namespace Splitio.Services.Common { public interface IEventsManager { - void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata, List eventsToNotify); + void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata); void Register(E sdkEvent, EventHandler handler); void Unregister(E sdkEvent); } diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index 6bf5c2b9..f70de053 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -37,9 +37,7 @@ public void BlockUntilReady(int blockMilisecondsUntilReady) if (!_statusManager.WaitUntilReady(blockMilisecondsUntilReady)) { _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, - new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - _eventsManager)); + new EventMetadata(new Dictionary())); _telemetryInitProducer.RecordBURTimeout(); throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady} milliseconds"); } diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index c9854f23..84dc8dda 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -1,6 +1,5 @@ using Splitio.CommonLibraries; using Splitio.Domain; -using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Logger; using Splitio.Telemetry.Domain.Enums; @@ -12,12 +11,6 @@ namespace Splitio.Util { public class Helper { - public struct ValidSdkEvent - { - public SdkEvent SdkEvent { get; set; } - public bool Valid { get; set; } - } - public static List TakeFromList(List items, int size) { if (items == null) return new List(); @@ -91,144 +84,5 @@ public static string getFallbackConfig(FallbackTreatment fallbackTreatment) return null; } - - public static List GetSdkEventIfApplicable(SdkInternalEvent sdkInternalEvent, - EventsManager eventsManager) - { - ValidSdkEvent finalSdkEvent = new ValidSdkEvent - { - Valid = false, - SdkEvent = SdkEvent.SdkReady - }; - eventsManager.UpdateSdkInternalEventStatus(sdkInternalEvent, true); - List eventsToFire = new List(); - - ValidSdkEvent requireAnySdkEvent = CheckRequireAny(sdkInternalEvent, eventsManager.ManagerConfig); - if (requireAnySdkEvent.Valid) - { - if ((!eventsManager.EventAlreadyTriggered(requireAnySdkEvent.SdkEvent) - && ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManager.ManagerConfig) == 1) || ExecutionLimit(requireAnySdkEvent.SdkEvent, eventsManager.ManagerConfig) == -1) - { - finalSdkEvent.SdkEvent = requireAnySdkEvent.SdkEvent; - } - - finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent, eventsManager) - && CheckSuppressedBy(finalSdkEvent.SdkEvent, eventsManager); - } - - if (finalSdkEvent.Valid) - { - eventsToFire.Add(finalSdkEvent.SdkEvent); - } - - foreach (SdkEvent sdkEvent in CheckRequireAll(eventsManager)) - { - eventsToFire.Add(sdkEvent); - } - - return eventsToFire; - } - - private static List CheckRequireAll( - EventsManager eventsManager) - { - List events = new List(); - foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.RequireAll) - { - bool finalStatus = true; - foreach (var val in kvp.Value) - { - finalStatus &= eventsManager.GetSdkInternalEventStatus(val); - } - if (finalStatus - && CheckPrerequisites(kvp.Key, eventsManager) - && ((ExecutionLimit(kvp.Key, eventsManager.ManagerConfig) == 1 && !eventsManager.EventAlreadyTriggered(kvp.Key)) - || (ExecutionLimit(kvp.Key, eventsManager.ManagerConfig) == -1)) - && kvp.Value.Count > 0) - { - events.Add(kvp.Key); - } - } - - return events; - } - - private static bool CheckPrerequisites(SdkEvent sdkEvent, - EventsManager eventsManager) - { - foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.Prerequisites) - { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => !eventsManager.EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } - } - - return true; - } - - private static bool CheckSuppressedBy(SdkEvent sdkEvent, - EventsManager eventsManager) - { - foreach (KeyValuePair> kvp in eventsManager.ManagerConfig.SuppressedBy) - { - if (kvp.Key == sdkEvent) - { - if (kvp.Value.Any(x => eventsManager.EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } - } - - return true; - } - - private static int ExecutionLimit(SdkEvent sdkEvent, EventsManagerConfig eventsManagerConfig) - { - if (!eventsManagerConfig.ExecutionLimits.ContainsKey(sdkEvent)) - return -1; - - eventsManagerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); - return limit; - } - - private static ValidSdkEvent CheckRequireAny(SdkInternalEvent sdkInternalEvent, EventsManagerConfig eventsManagerConfig) - { - ValidSdkEvent validSdkEvent = new ValidSdkEvent - { - Valid = false, - SdkEvent = SdkEvent.SdkUpdate - }; - - foreach (KeyValuePair> kvp in eventsManagerConfig.RequireAny) - { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = kvp.Key; - return validSdkEvent; - } - } - - return validSdkEvent; - } - - public static void BuildInternalSdkEventStatus(EventsManager eventsManager) - { - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkReady, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.RuleBasedSegmentsUpdated, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SdkTimedOut, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.SegmentsUpdated, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagKilledNotification, false); - eventsManager.UpdateSdkInternalEventStatus(SdkInternalEvent.FlagsUpdated, false); - } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index e3ba2df2..d4f207c5 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -154,17 +154,15 @@ public void Contains_ShouldReturnTrue() public void Update_ShouldNotifyEvent() { // Arrange - Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; - var toNotify = new List { { "segment-to-add" } }; + var toNotify = new List { { "segment-to-add" }, { "segment-to-remove" } }; PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act SdkUpdate = false; @@ -174,7 +172,7 @@ public void Update_ShouldNotifyEvent() Assert.IsTrue(SdkUpdate); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; - Assert.IsTrue(rbsegments.Count == 2); + Assert.IsTrue(rbsegments.Count == 3); Assert.IsTrue(rbsegments.Contains("segment-to-add")); Assert.IsTrue(rbsegments.Contains("segment-to-remove")); } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index 806d67b2..d44a7343 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -7,7 +7,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; -using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Cache { @@ -60,13 +59,11 @@ public async Task NotifyEventsTest() { //Arrange var segmentName = "segment_test"; - Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); var toNotify = new List { { segmentName } }; PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); //Act SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index b81611a4..fd9bac22 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -105,7 +105,6 @@ public void NotifyEventsTest() { //Arrange var eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; @@ -113,8 +112,7 @@ public void NotifyEventsTest() PublicSdkUpdateHandler += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 5d3b4c18..9fb65e65 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -27,7 +27,6 @@ public SplitCacheAsyncTests() _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); _eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(_eventsManager); _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); } @@ -197,8 +196,7 @@ public async Task NotifyUpdateEventTest() PublicSdkUpdateHandler += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, _eventsManager)); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); SdkUpdate = false; _cache.Update(toAdd, new List(), -1); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 35a59f45..3d545067 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -245,7 +245,6 @@ public void NotifyUpdateEventTest() { // Arrange. var eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; @@ -253,8 +252,7 @@ public void NotifyUpdateEventTest() PublicSdkUpdateHandler += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary()), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act. SdkUpdate = false; diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs index 95ecd3ba..05f826be 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs @@ -4,15 +4,17 @@ using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Shared.Classes; +using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Client { [TestClass] public class LocalhostClientUnitTests - { + { private readonly string rootFilePath; private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; private readonly EventsManager _eventsManager; + private bool SdkReady = false; public LocalhostClientUnitTests() { @@ -62,7 +64,7 @@ public void TrackShouldNotStoreEvents() //Arrange var splitClient = new LocalhostClientForTesting($"{rootFilePath}test.splits", _fallbackTreatmentCalculator); splitClient.BlockUntilReady(1000); - + //Act var result = splitClient.Track("test", "test", "test"); diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index 83ca9c24..8bd2f7b9 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -31,10 +31,9 @@ public void TestFireReadyEvent() { //Arrange EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); var gates = new InMemoryReadinessGatesCache(eventsManager); PublicSdkUpdateHandler += sdkReady_callback; - eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); + eventsManager.Register(SdkEvent.SdkReady, PublicSdkUpdateHandler); //Act gates.SetReady(); diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 558fa68c..3c1a25d9 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -10,6 +10,7 @@ namespace Splitio_Tests.Unit_Tests.Common public class EventsManagerTests { private bool SdkReady = false; + private bool SdkReady2 = false; private bool SdkTimedOut = false; private bool SdkUpdate = false; private EventMetadata eMetadata = null; @@ -23,49 +24,36 @@ public void TestFiringEvents() //Act EventsManagerConfig config = new EventsManagerConfig(); EventsManager eventsManager = new EventsManager(config); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); PublicSdkReadyHandler += sdkReady_callback; + PublicSdkReadyHandler += sdkReady_callback2; PublicSdkUpdateHandler += sdkUpdate_callback; PublicSdkTimedOutHandler += sdkTimedOut_callback; - Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventsManager.Register(SdkEvent.SdkReady, sdkReady_callback); - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - eventsManager)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - eventsManager)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - eventsManager)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - eventsManager)); + eventsManager.Register(SdkEvent.SdkReady, PublicSdkReadyHandler); + eventsManager.Register(SdkEvent.SdkUpdate, PublicSdkUpdateHandler); + + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet - eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - eventsManager)); + eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); @@ -73,30 +61,24 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - List eventsToNotify = Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkReady, - eventsManager); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData), - eventsToNotify); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReady); + Assert.IsTrue(SdkReady2); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.Register(SdkEvent.SdkReadyTimeout, sdkTimedOut_callback); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SdkTimedOut, - eventsManager)); + eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReady); Assert.IsFalse(SdkUpdate); Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagKilledNotification, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -104,9 +86,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.SegmentsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -114,9 +94,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.RuleBasedSegmentsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -124,9 +102,7 @@ public void TestFiringEvents() VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -136,9 +112,7 @@ public void TestFiringEvents() eventsManager.Unregister(SdkEvent.SdkUpdate); eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData), - Splitio.Util.Helper.GetSdkEventIfApplicable(SdkInternalEvent.FlagsUpdated, - eventsManager)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOut); Assert.IsFalse(SdkReady); @@ -148,6 +122,7 @@ public void TestFiringEvents() void ResetAllVariables() { SdkReady = false; + SdkReady2 = false; SdkTimedOut = false; eMetadata = null; SdkUpdate = false; @@ -173,6 +148,12 @@ private void sdkReady_callback(object sender, EventMetadata metadata) eMetadata = metadata; } + private void sdkReady_callback2(object sender, EventMetadata metadata) + { + SdkReady2 = true; + eMetadata = metadata; + } + private void sdkTimedOut_callback(object sender, EventMetadata metadata) { SdkTimedOut = true; diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index d5204d8e..120072f3 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -23,10 +23,9 @@ public void TestFireTimedOutEvent() Mock statusManager = new Mock(); Mock telemetryProducer = new Mock(); EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); - Splitio.Util.Helper.BuildInternalSdkEventStatus(eventsManager); var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, eventsManager); PublicSdkUpdateHandler += SdkTimedOut_callback; - eventsManager.Register(SdkEvent.SdkReadyTimeout, SdkTimedOut_callback); + eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkUpdateHandler); statusManager .Setup(mock => mock.WaitUntilReady(1)) .Returns(false); From 4af93a3f90195e9d1c5620340d40362243101919 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 18:36:42 -0800 Subject: [PATCH 47/87] polish --- .../Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 4 ++-- src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs | 4 ++-- src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 30c1fbc9..998e419a 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -12,10 +12,10 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache { private readonly ConcurrentDictionary _cache; private long _changeNumber; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, - EventsManager eventsManger, + IEventsManager eventsManger, long changeNumber = -1) { _cache = cache; diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index c0b5d8a5..1a687722 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -15,9 +15,9 @@ public class InMemorySegmentCache : ISegmentCache private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemorySegmentCache)); private readonly ConcurrentDictionary _segments; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; - public InMemorySegmentCache(ConcurrentDictionary segments, EventsManager eventsManger) + public InMemorySegmentCache(ConcurrentDictionary segments, IEventsManager eventsManger) { _segments = segments; _eventsManager = eventsManger; diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index d222aa12..73bddb5d 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -20,12 +20,12 @@ public class InMemorySplitCache : IFeatureFlagCache private readonly ConcurrentDictionary _featureFlags; private readonly ConcurrentDictionary _trafficTypes; private readonly ConcurrentDictionary> _flagSets; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; private long _changeNumber; public InMemorySplitCache(ConcurrentDictionary featureFlags, - IFlagSetsFilter flagSetsFilter, EventsManager eventsManger, + IFlagSetsFilter flagSetsFilter, IEventsManager eventsManger, long changeNumber = -1) { _featureFlags = featureFlags; From c5ea092ed1ee5d9a75cf3ded68a1a9abeae1fea0 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 18:45:59 -0800 Subject: [PATCH 48/87] polish --- .../Services/Cache/Classes/InMemoryReadinessGatesCache.cs | 4 ++-- .../Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 4 ++-- src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs | 4 ++-- src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs | 4 ++-- src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs | 4 +--- src/Splitio/Services/Client/Classes/SplitClient.cs | 4 ++-- .../Shared/Classes/SelfRefreshingBlockUntilReadyService.cs | 4 ++-- 7 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index d0a7d441..f784fbbe 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -10,9 +10,9 @@ public class InMemoryReadinessGatesCache : IStatusManager { private readonly CountdownEvent _sdkReady = new CountdownEvent(1); private readonly CountdownEvent _sdkDestroyed = new CountdownEvent(1); - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; - public InMemoryReadinessGatesCache(EventsManager eventsManager) + public InMemoryReadinessGatesCache(IEventsManager eventsManager) { _eventsManager = eventsManager; } diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 30c1fbc9..998e419a 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -12,10 +12,10 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache { private readonly ConcurrentDictionary _cache; private long _changeNumber; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, - EventsManager eventsManger, + IEventsManager eventsManger, long changeNumber = -1) { _cache = cache; diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index c0b5d8a5..1a687722 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -15,9 +15,9 @@ public class InMemorySegmentCache : ISegmentCache private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemorySegmentCache)); private readonly ConcurrentDictionary _segments; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; - public InMemorySegmentCache(ConcurrentDictionary segments, EventsManager eventsManger) + public InMemorySegmentCache(ConcurrentDictionary segments, IEventsManager eventsManger) { _segments = segments; _eventsManager = eventsManger; diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index d222aa12..73bddb5d 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -20,12 +20,12 @@ public class InMemorySplitCache : IFeatureFlagCache private readonly ConcurrentDictionary _featureFlags; private readonly ConcurrentDictionary _trafficTypes; private readonly ConcurrentDictionary> _flagSets; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; private long _changeNumber; public InMemorySplitCache(ConcurrentDictionary featureFlags, - IFlagSetsFilter flagSetsFilter, EventsManager eventsManger, + IFlagSetsFilter flagSetsFilter, IEventsManager eventsManger, long changeNumber = -1) { _featureFlags = featureFlags; diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 4cd7c08a..7d513bc5 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -52,15 +52,13 @@ public class SelfRefreshingClient : SplitClient private IRuleBasedSegmentCache _ruleBasedSegmentCache; private IUpdater _ruleBasedSegmentUpdater; private readonly new FallbackTreatmentCalculator _fallbackTreatmentCalculator; - private readonly EventsManager _eventsManager; public SelfRefreshingClient(string apiKey, ConfigurationOptions config, FallbackTreatmentCalculator fallbackTreatmentCalculator, - EventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) + IEventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) { _config = (SelfRefreshingConfig)_configService.ReadConfig(config, ConfigTypes.InMemory); _fallbackTreatmentCalculator = fallbackTreatmentCalculator; - _eventsManager = eventsManager; BuildFlagSetsFilter(_config.FlagSetsFilter); BuildSplitCache(); diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index e9c60ef6..d37ed283 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,13 +63,13 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; - protected EventsManager _eventsManager; + protected IEventsManager _eventsManager; public event EventHandler PublicSdkReadyHandler; public event EventHandler PublicSdkUpdateHandler; public event EventHandler PublicSdkTimedOutHandler; protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, - EventsManager eventsManager) + IEventsManager eventsManager) { ApiKey = apikey; _eventsManager = eventsManager; diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index f70de053..5edb873c 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -15,10 +15,10 @@ public class SelfRefreshingBlockUntilReadyService : IBlockUntilReadyService private readonly IStatusManager _statusManager; private readonly ITelemetryInitProducer _telemetryInitProducer; - private readonly EventsManager _eventsManager; + private readonly IEventsManager _eventsManager; public SelfRefreshingBlockUntilReadyService(IStatusManager statusManager, ITelemetryInitProducer telemetryInitProducer, - EventsManager eventsManager) + IEventsManager eventsManager) { _statusManager = statusManager; _telemetryInitProducer = telemetryInitProducer; From 6d5071550da63254d7d0acd4ba86fa55a53f003c Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 20:34:21 -0800 Subject: [PATCH 49/87] polish --- src/Splitio/Services/Common/EventsManager.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 79ad8373..d08a57b9 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -131,7 +131,6 @@ public List GetSdkEventIfApplicable(I sdkInternalEvent) ValidSdkEvent finalSdkEvent = new ValidSdkEvent { Valid = false -// SdkEvent = SdkEvent.SdkReady }; UpdateSdkInternalEventStatus(sdkInternalEvent, true); List eventsToFire = new List(); @@ -147,11 +146,11 @@ public List GetSdkEventIfApplicable(I sdkInternalEvent) finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent) && CheckSuppressedBy(finalSdkEvent.SdkEvent); - } - if (finalSdkEvent.Valid) - { - eventsToFire.Add(finalSdkEvent.SdkEvent); + if (finalSdkEvent.Valid) + { + eventsToFire.Add(finalSdkEvent.SdkEvent); + } } foreach (E sdkEvent in CheckRequireAll()) @@ -235,7 +234,6 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) ValidSdkEvent validSdkEvent = new ValidSdkEvent { Valid = false -// SdkEvent = SdkEvent.SdkUpdate }; foreach (KeyValuePair> kvp in _managerConfig.RequireAny) From e7af0f783970929da0849b8e7c7364ff1dd7c0dd Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 22 Dec 2025 20:36:24 -0800 Subject: [PATCH 50/87] polish --- src/Splitio/Services/Common/EventsManager.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 79ad8373..d08a57b9 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -131,7 +131,6 @@ public List GetSdkEventIfApplicable(I sdkInternalEvent) ValidSdkEvent finalSdkEvent = new ValidSdkEvent { Valid = false -// SdkEvent = SdkEvent.SdkReady }; UpdateSdkInternalEventStatus(sdkInternalEvent, true); List eventsToFire = new List(); @@ -147,11 +146,11 @@ public List GetSdkEventIfApplicable(I sdkInternalEvent) finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent) && CheckSuppressedBy(finalSdkEvent.SdkEvent); - } - if (finalSdkEvent.Valid) - { - eventsToFire.Add(finalSdkEvent.SdkEvent); + if (finalSdkEvent.Valid) + { + eventsToFire.Add(finalSdkEvent.SdkEvent); + } } foreach (E sdkEvent in CheckRequireAll()) @@ -235,7 +234,6 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) ValidSdkEvent validSdkEvent = new ValidSdkEvent { Valid = false -// SdkEvent = SdkEvent.SdkUpdate }; foreach (KeyValuePair> kvp in _managerConfig.RequireAny) From b93bdc0168ae5634e0d6fd3af34e55f8f8ec2408 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 11:49:15 -0800 Subject: [PATCH 51/87] refactor event delivery to use action callback --- .../Cache/Classes/InMemorySplitCache.cs | 1 + .../Services/Client/Classes/SplitClient.cs | 7 +- .../Client/Interfaces/ISplitClient.cs | 5 + src/Splitio/Services/Common/EventDelivery.cs | 7 +- src/Splitio/Services/Common/EventsManager.cs | 45 ++---- src/Splitio/Services/Common/IEventDelivery.cs | 2 +- src/Splitio/Services/Common/IEventsManager.cs | 7 +- .../InMemory/RuleBasedSegmentCacheTests.cs | 27 +++- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 27 +++- .../Cache/InMemory/SegmentCacheTests.cs | 31 ++-- .../Cache/InMemory/SplitCacheAsyncTests.cs | 31 ++-- .../Cache/InMemory/SplitCacheTests.cs | 31 ++-- .../Unit Tests/Common/EventDeliveryTests.cs | 8 +- .../Unit Tests/Common/EventsManagerTests.cs | 142 ++++++++++-------- 14 files changed, 214 insertions(+), 157 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index 73bddb5d..1a99fd8c 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -74,6 +74,7 @@ public void Update(List toAdd, List toRemove, long till) { DecreaseTrafficTypeCount(removedSplit); RemoveFromFlagSets(removedSplit.name, removedSplit.Sets); + eventsFlags.Add(featureFlagName); } } diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 4372c344..c8d383f9 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,9 +63,10 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; + + public event EventHandler SdkReady; + public event EventHandler SdkUpdate; + public event EventHandler SdkTimedOut; protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator) { diff --git a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs index 60e0b751..a18982dd 100644 --- a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs +++ b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs @@ -1,10 +1,15 @@ using Splitio.Domain; +using System; using System.Collections.Generic; namespace Splitio.Services.Client.Interfaces { public interface ISplitClient : ISplitClientAsync { + event EventHandler SdkReady; + event EventHandler SdkUpdate; + event EventHandler SdkTimedOut; + /// /// Returns the treatment to show this key for this feature flag. /// The set of treatments for a feature flag can be configured on the Split user interface. diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index b97e7a32..38b04ffe 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,4 +1,5 @@ -using Splitio.Services.Logger; +using Splitio.Domain; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; @@ -8,14 +9,14 @@ public class EventDelivery : IEventDelivery { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); - public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler) + public virtual void Deliver(E sdkEvent, M eventMetadata, Action handler) { if (handler != null) { _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { - handler.Invoke(this, eventMetadata); + handler.Invoke(eventMetadata); } catch (Exception e) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index d08a57b9..d891e883 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -19,12 +19,12 @@ public struct ValidSdkEvent private struct PublicEventProperties { public bool Triggered; - public EventHandler EventHandler; + public Action EventHandler; } private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - private readonly EventDelivery _eventDelivery; + public readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); public EventManagerConfigData _managerConfig { get; private set; } @@ -37,7 +37,7 @@ public EventsManager(EventManagerConfigData eventsManagerConfig) } #region Public Methods - public void Register(E sdkEvent, EventHandler handler) + public void Register(E sdkEvent, Action handler) { if (_activeSubscriptions.TryGetValue(sdkEvent, out var _)) { @@ -116,7 +116,7 @@ private void SetSdkEventTriggered(E sdkEvent) _activeSubscriptions.TryUpdate(sdkEvent, newEventData, eventData); } - private EventHandler GetEventHandler(E sdkEvent) + private Action GetEventHandler(E sdkEvent) { if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { @@ -186,17 +186,10 @@ private List CheckRequireAll() private bool CheckPrerequisites(E sdkEvent) { - foreach (KeyValuePair> kvp in _managerConfig.Prerequisites) + foreach (var item in _managerConfig.Prerequisites.Where(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => !EventAlreadyTriggered(x)))) { - if (kvp.Key.Equals(sdkEvent)) - { - if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return false; } return true; @@ -204,17 +197,10 @@ private bool CheckPrerequisites(E sdkEvent) private bool CheckSuppressedBy(E sdkEvent) { - foreach (KeyValuePair> kvp in _managerConfig.SuppressedBy) + foreach (var item in _managerConfig.SuppressedBy.Where(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => EventAlreadyTriggered(x)))) { - if (kvp.Key.Equals(sdkEvent)) - { - if (kvp.Value.Any(x => EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return false; } return true; @@ -236,14 +222,11 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) Valid = false }; - foreach (KeyValuePair> kvp in _managerConfig.RequireAny) + foreach (var item in _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent))) { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = kvp.Key; - return validSdkEvent; - } + validSdkEvent.Valid = true; + validSdkEvent.SdkEvent = item.Key; + return validSdkEvent; } return validSdkEvent; diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs index 550cfbbf..69ae709f 100644 --- a/src/Splitio/Services/Common/IEventDelivery.cs +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -5,6 +5,6 @@ namespace Splitio.Services.Common { public interface IEventDelivery { - void Deliver(E sdkEvent, M eventMetadata, EventHandler handler); + void Deliver(E sdkEvent, M eventMetadata, Action handler); } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index 23e719c7..ac5f3739 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,13 +1,12 @@ -using Splitio.Domain; -using System; -using System.Collections.Generic; +using System; namespace Splitio.Services.Common { public interface IEventsManager { void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata); - void Register(E sdkEvent, EventHandler handler); + void Register(E sdkEvent, Action handler); void Unregister(E sdkEvent); + bool EventAlreadyTriggered(E sdkEvent); } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index d4f207c5..b43c27ca 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -14,9 +14,10 @@ public class RuleBasedSegmentCacheTests { private InMemoryRuleBasedSegmentCache _segmentCache; private EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; [TestInitialize] public void Setup() @@ -159,17 +160,17 @@ public void Update_ShouldNotifyEvent() var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; var toNotify = new List { { "segment-to-add" }, { "segment-to-remove" } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act - SdkUpdate = false; + SdkUpdateFlag = false; _segmentCache.Update(new List { segmentToAdd, segmentToRemove }, new List { segmentToRemove.Name }, till); // Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; Assert.IsTrue(rbsegments.Count == 3); @@ -179,8 +180,18 @@ public void Update_ShouldNotifyEvent() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index d44a7343..64ff38f3 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -15,9 +15,10 @@ public class SegmentCacheAsyncTests { private readonly ISegmentCache _cache; private EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SegmentCacheAsyncTests() { @@ -60,17 +61,17 @@ public async Task NotifyEventsTest() //Arrange var segmentName = "segment_test"; var toNotify = new List { { segmentName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); //Act - SdkUpdate = false; + SdkUpdateFlag = false; _cache.AddToSegment(segmentName, new List { "abcd", "zzzzf" }); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); string segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); @@ -78,8 +79,18 @@ public async Task NotifyEventsTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index fd9bac22..235d9408 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -11,9 +11,10 @@ namespace Splitio_Tests.Unit_Tests.Cache [TestClass] public class SegmentCacheTests { - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; [TestMethod] public void RegisterSegmentTest() @@ -109,28 +110,28 @@ public void NotifyEventsTest() var keys = new List { "1234" }; var segmentName = "test"; var toNotify = new List { { segmentName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act - SdkUpdate = false; + SdkUpdateFlag = false; segmentCache.AddToSegment(segmentName, keys); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); string segment = (string) eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); // Act - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; segmentCache.RemoveFromSegment(segmentName, keys); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); @@ -138,8 +139,18 @@ public void NotifyEventsTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 9fb65e65..c02d905f 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -18,9 +18,10 @@ public class SplitCacheAsyncTests private readonly IFlagSetsFilter _flagSetsFilter; private readonly IFeatureFlagCache _cache; private readonly EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SplitCacheAsyncTests() { @@ -193,12 +194,12 @@ public async Task NotifyUpdateEventTest() }); toNotify.Add($"feature-flag-{i}"); } - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); - SdkUpdate = false; + SdkUpdateFlag = false; _cache.Update(toAdd, new List(), -1); // Act. @@ -206,7 +207,7 @@ public async Task NotifyUpdateEventTest() // Assert. Assert.AreEqual(5, result.Count); - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 5); @@ -215,11 +216,11 @@ public async Task NotifyUpdateEventTest() Assert.IsTrue(flags.Contains($"feature-flag-{i}")); } - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; _cache.Kill(123, "feature-flag-1", "off"); - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); @@ -228,8 +229,18 @@ public async Task NotifyUpdateEventTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 3d545067..33a0889d 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -15,9 +15,10 @@ namespace Splitio_Tests.Unit_Tests.Cache public class SplitCacheTests { private readonly Mock _flagSetsFilter; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SplitCacheTests() { @@ -249,29 +250,29 @@ public void NotifyUpdateEventTest() var splitName = "test1"; var toNotify = new List { { splitName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act. - SdkUpdate = false; + SdkUpdateFlag = false; splitCache.Update(new List { new ParsedSplit() { name = splitName } }, new List(), -1); // Assert. - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); Assert.IsTrue(flags.Contains(splitName)); // Act. - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; splitCache.Kill(123, splitName, "off"); // Assert. - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); @@ -280,8 +281,18 @@ public void NotifyUpdateEventTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index 80711087..1619f9d1 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Common; -using System; using System.Collections.Generic; namespace Splitio_Tests.Unit_Tests.Common @@ -11,7 +10,6 @@ public class EventDeliveryTests { private bool SdkReady = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkReadyHandler; [TestMethod] public void TestFiringEvents() @@ -19,14 +17,12 @@ public void TestFiringEvents() //Act EventDelivery eventDelivery = new EventDelivery(); - PublicSdkReadyHandler += sdkReady_callback; - Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), PublicSdkReadyHandler); + eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), sdkReady_callback); Assert.IsTrue(SdkReady); VerifyMetadata(eMetadata); @@ -40,7 +36,7 @@ void VerifyMetadata(EventMetadata eMetdata) Assert.IsTrue(flags.Contains("flag1")); } - private void sdkReady_callback(object sender, EventMetadata metadata) + private void sdkReady_callback(EventMetadata metadata) { SdkReady = true; eMetadata = metadata; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 3c1a25d9..50c3ee78 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -9,14 +9,14 @@ namespace Splitio_Tests.Unit_Tests.Common [TestClass] public class EventsManagerTests { - private bool SdkReady = false; - private bool SdkReady2 = false; - private bool SdkTimedOut = false; - private bool SdkUpdate = false; + private bool SdkReadyFlag = false; + private bool SdkReadyFlag2 = false; + private bool SdkTimedOutFlag = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; + public event EventHandler SdkReady; + public event EventHandler SdkUpdate; + public event EventHandler SdkTimedOut; [TestMethod] public void TestFiringEvents() @@ -25,107 +25,107 @@ public void TestFiringEvents() EventsManagerConfig config = new EventsManagerConfig(); EventsManager eventsManager = new EventsManager(config); - PublicSdkReadyHandler += sdkReady_callback; - PublicSdkReadyHandler += sdkReady_callback2; - PublicSdkUpdateHandler += sdkUpdate_callback; - PublicSdkTimedOutHandler += sdkTimedOut_callback; + SdkReady += sdkReady_callback; + SdkReady += sdkReady_callback2; + SdkUpdate += sdkUpdate_callback; + SdkTimedOut += sdkTimedOut_callback; Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventsManager.Register(SdkEvent.SdkReady, PublicSdkReadyHandler); - eventsManager.Register(SdkEvent.SdkUpdate, PublicSdkUpdateHandler); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); // not fired as it is not registered yet - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsTrue(SdkTimedOut); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsTrue(SdkTimedOutFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkReady); - Assert.IsTrue(SdkReady2); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); + System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsTrue(SdkReadyFlag); + Assert.IsTrue(SdkReadyFlag2); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); // not fired as suppressed by sdkReady ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); eventsManager.Unregister(SdkEvent.SdkUpdate); eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); } void ResetAllVariables() { - SdkReady = false; - SdkReady2 = false; - SdkTimedOut = false; + SdkReadyFlag = false; + SdkReadyFlag2 = false; + SdkTimedOutFlag = false; eMetadata = null; - SdkUpdate = false; + SdkUpdateFlag = false; } void VerifyMetadata(EventMetadata eMetdata) @@ -138,26 +138,42 @@ void VerifyMetadata(EventMetadata eMetdata) private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } private void sdkReady_callback(object sender, EventMetadata metadata) { - SdkReady = true; + SdkReadyFlag = true; eMetadata = metadata; } private void sdkReady_callback2(object sender, EventMetadata metadata) { - SdkReady2 = true; + SdkReadyFlag2 = true; eMetadata = metadata; } private void sdkTimedOut_callback(object sender, EventMetadata metadata) { - SdkTimedOut = true; + SdkTimedOutFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } + + private void TriggerSdkTimeout(EventMetadata metaData) + { + SdkTimedOut?.Invoke(this, metaData); + } + } } From 4520c7cb2bb613be91ac0fb37a8ebb5d1bcd65f8 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 12:15:05 -0800 Subject: [PATCH 52/87] refactor delivery and event manager to use action callback --- .../Cache/Classes/InMemorySplitCache.cs | 1 + .../Services/Client/Classes/SplitClient.cs | 11 +- .../Client/Interfaces/ISplitClient.cs | 5 + src/Splitio/Services/Common/EventDelivery.cs | 7 +- src/Splitio/Services/Common/EventsManager.cs | 45 ++---- src/Splitio/Services/Common/IEventDelivery.cs | 2 +- src/Splitio/Services/Common/IEventsManager.cs | 7 +- .../InMemory/RuleBasedSegmentCacheTests.cs | 27 +++- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 27 +++- .../Cache/InMemory/SegmentCacheTests.cs | 31 ++-- .../Cache/InMemory/SplitCacheAsyncTests.cs | 31 ++-- .../Cache/InMemory/SplitCacheTests.cs | 31 ++-- .../Client/SdkReadinessGatesUnitTests.cs | 17 ++- .../Unit Tests/Common/EventDeliveryTests.cs | 8 +- .../Unit Tests/Common/EventsManagerTests.cs | 142 ++++++++++-------- ...lfRefreshingBlockUntilReadyServiceTests.cs | 19 ++- 16 files changed, 238 insertions(+), 173 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index 73bddb5d..1a99fd8c 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -74,6 +74,7 @@ public void Update(List toAdd, List toRemove, long till) { DecreaseTrafficTypeCount(removedSplit); RemoveFromFlagSets(removedSplit.name, removedSplit.Sets); + eventsFlags.Add(featureFlagName); } } diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index d37ed283..6e9465c0 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -64,16 +64,15 @@ public abstract class SplitClient : ISplitClient protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; protected IEventsManager _eventsManager; - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; - protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, - IEventsManager eventsManager) + public event EventHandler SdkReady; + public event EventHandler SdkUpdate; + public event EventHandler SdkTimedOut; + + protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, IEventsManager eventsManager) { ApiKey = apikey; _eventsManager = eventsManager; - _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _wrapperAdapter = WrapperAdapter.Instance(); _keyValidator = new KeyValidator(); diff --git a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs index 60e0b751..a18982dd 100644 --- a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs +++ b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs @@ -1,10 +1,15 @@ using Splitio.Domain; +using System; using System.Collections.Generic; namespace Splitio.Services.Client.Interfaces { public interface ISplitClient : ISplitClientAsync { + event EventHandler SdkReady; + event EventHandler SdkUpdate; + event EventHandler SdkTimedOut; + /// /// Returns the treatment to show this key for this feature flag. /// The set of treatments for a feature flag can be configured on the Split user interface. diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index b97e7a32..38b04ffe 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,4 +1,5 @@ -using Splitio.Services.Logger; +using Splitio.Domain; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; @@ -8,14 +9,14 @@ public class EventDelivery : IEventDelivery { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); - public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler) + public virtual void Deliver(E sdkEvent, M eventMetadata, Action handler) { if (handler != null) { _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { - handler.Invoke(this, eventMetadata); + handler.Invoke(eventMetadata); } catch (Exception e) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index d08a57b9..d891e883 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -19,12 +19,12 @@ public struct ValidSdkEvent private struct PublicEventProperties { public bool Triggered; - public EventHandler EventHandler; + public Action EventHandler; } private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - private readonly EventDelivery _eventDelivery; + public readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); public EventManagerConfigData _managerConfig { get; private set; } @@ -37,7 +37,7 @@ public EventsManager(EventManagerConfigData eventsManagerConfig) } #region Public Methods - public void Register(E sdkEvent, EventHandler handler) + public void Register(E sdkEvent, Action handler) { if (_activeSubscriptions.TryGetValue(sdkEvent, out var _)) { @@ -116,7 +116,7 @@ private void SetSdkEventTriggered(E sdkEvent) _activeSubscriptions.TryUpdate(sdkEvent, newEventData, eventData); } - private EventHandler GetEventHandler(E sdkEvent) + private Action GetEventHandler(E sdkEvent) { if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { @@ -186,17 +186,10 @@ private List CheckRequireAll() private bool CheckPrerequisites(E sdkEvent) { - foreach (KeyValuePair> kvp in _managerConfig.Prerequisites) + foreach (var item in _managerConfig.Prerequisites.Where(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => !EventAlreadyTriggered(x)))) { - if (kvp.Key.Equals(sdkEvent)) - { - if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return false; } return true; @@ -204,17 +197,10 @@ private bool CheckPrerequisites(E sdkEvent) private bool CheckSuppressedBy(E sdkEvent) { - foreach (KeyValuePair> kvp in _managerConfig.SuppressedBy) + foreach (var item in _managerConfig.SuppressedBy.Where(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => EventAlreadyTriggered(x)))) { - if (kvp.Key.Equals(sdkEvent)) - { - if (kvp.Value.Any(x => EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return false; } return true; @@ -236,14 +222,11 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) Valid = false }; - foreach (KeyValuePair> kvp in _managerConfig.RequireAny) + foreach (var item in _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent))) { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = kvp.Key; - return validSdkEvent; - } + validSdkEvent.Valid = true; + validSdkEvent.SdkEvent = item.Key; + return validSdkEvent; } return validSdkEvent; diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs index 550cfbbf..69ae709f 100644 --- a/src/Splitio/Services/Common/IEventDelivery.cs +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -5,6 +5,6 @@ namespace Splitio.Services.Common { public interface IEventDelivery { - void Deliver(E sdkEvent, M eventMetadata, EventHandler handler); + void Deliver(E sdkEvent, M eventMetadata, Action handler); } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index 23e719c7..ac5f3739 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,13 +1,12 @@ -using Splitio.Domain; -using System; -using System.Collections.Generic; +using System; namespace Splitio.Services.Common { public interface IEventsManager { void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata); - void Register(E sdkEvent, EventHandler handler); + void Register(E sdkEvent, Action handler); void Unregister(E sdkEvent); + bool EventAlreadyTriggered(E sdkEvent); } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index d4f207c5..b43c27ca 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -14,9 +14,10 @@ public class RuleBasedSegmentCacheTests { private InMemoryRuleBasedSegmentCache _segmentCache; private EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; [TestInitialize] public void Setup() @@ -159,17 +160,17 @@ public void Update_ShouldNotifyEvent() var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; var toNotify = new List { { "segment-to-add" }, { "segment-to-remove" } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act - SdkUpdate = false; + SdkUpdateFlag = false; _segmentCache.Update(new List { segmentToAdd, segmentToRemove }, new List { segmentToRemove.Name }, till); // Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; Assert.IsTrue(rbsegments.Count == 3); @@ -179,8 +180,18 @@ public void Update_ShouldNotifyEvent() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index d44a7343..64ff38f3 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -15,9 +15,10 @@ public class SegmentCacheAsyncTests { private readonly ISegmentCache _cache; private EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SegmentCacheAsyncTests() { @@ -60,17 +61,17 @@ public async Task NotifyEventsTest() //Arrange var segmentName = "segment_test"; var toNotify = new List { { segmentName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); //Act - SdkUpdate = false; + SdkUpdateFlag = false; _cache.AddToSegment(segmentName, new List { "abcd", "zzzzf" }); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); string segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); @@ -78,8 +79,18 @@ public async Task NotifyEventsTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index fd9bac22..235d9408 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -11,9 +11,10 @@ namespace Splitio_Tests.Unit_Tests.Cache [TestClass] public class SegmentCacheTests { - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; [TestMethod] public void RegisterSegmentTest() @@ -109,28 +110,28 @@ public void NotifyEventsTest() var keys = new List { "1234" }; var segmentName = "test"; var toNotify = new List { { segmentName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act - SdkUpdate = false; + SdkUpdateFlag = false; segmentCache.AddToSegment(segmentName, keys); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); string segment = (string) eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); // Act - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; segmentCache.RemoveFromSegment(segmentName, keys); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); @@ -138,8 +139,18 @@ public void NotifyEventsTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 9fb65e65..c02d905f 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -18,9 +18,10 @@ public class SplitCacheAsyncTests private readonly IFlagSetsFilter _flagSetsFilter; private readonly IFeatureFlagCache _cache; private readonly EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SplitCacheAsyncTests() { @@ -193,12 +194,12 @@ public async Task NotifyUpdateEventTest() }); toNotify.Add($"feature-flag-{i}"); } - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); - SdkUpdate = false; + SdkUpdateFlag = false; _cache.Update(toAdd, new List(), -1); // Act. @@ -206,7 +207,7 @@ public async Task NotifyUpdateEventTest() // Assert. Assert.AreEqual(5, result.Count); - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 5); @@ -215,11 +216,11 @@ public async Task NotifyUpdateEventTest() Assert.IsTrue(flags.Contains($"feature-flag-{i}")); } - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; _cache.Kill(123, "feature-flag-1", "off"); - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); @@ -228,8 +229,18 @@ public async Task NotifyUpdateEventTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 3d545067..33a0889d 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -15,9 +15,10 @@ namespace Splitio_Tests.Unit_Tests.Cache public class SplitCacheTests { private readonly Mock _flagSetsFilter; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SplitCacheTests() { @@ -249,29 +250,29 @@ public void NotifyUpdateEventTest() var splitName = "test1"; var toNotify = new List { { splitName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act. - SdkUpdate = false; + SdkUpdateFlag = false; splitCache.Update(new List { new ParsedSplit() { name = splitName } }, new List(), -1); // Assert. - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); Assert.IsTrue(flags.Contains(splitName)); // Act. - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; splitCache.Kill(123, splitName, "off"); // Assert. - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); @@ -280,8 +281,18 @@ public void NotifyUpdateEventTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index 8bd2f7b9..c53d5252 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -9,9 +9,9 @@ namespace Splitio_Tests.Unit_Tests.Client [TestClass] public class InMemoryReadinessGatesCacheUnitTests { - private bool SdkReady = false; + private bool SdkReadyFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkReady; [TestMethod] public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() @@ -32,21 +32,26 @@ public void TestFireReadyEvent() //Arrange EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); var gates = new InMemoryReadinessGatesCache(eventsManager); - PublicSdkUpdateHandler += sdkReady_callback; - eventsManager.Register(SdkEvent.SdkReady, PublicSdkUpdateHandler); + SdkReady += sdkReady_callback; + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); //Act gates.SetReady(); // Assert. - Assert.IsTrue(SdkReady); + Assert.IsTrue(SdkReadyFlag); Assert.AreEqual(0, eMetadata.GetData().Count); } private void sdkReady_callback(object sender, EventMetadata metadata) { - SdkReady = true; + SdkReadyFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index 80711087..1619f9d1 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Common; -using System; using System.Collections.Generic; namespace Splitio_Tests.Unit_Tests.Common @@ -11,7 +10,6 @@ public class EventDeliveryTests { private bool SdkReady = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkReadyHandler; [TestMethod] public void TestFiringEvents() @@ -19,14 +17,12 @@ public void TestFiringEvents() //Act EventDelivery eventDelivery = new EventDelivery(); - PublicSdkReadyHandler += sdkReady_callback; - Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), PublicSdkReadyHandler); + eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), sdkReady_callback); Assert.IsTrue(SdkReady); VerifyMetadata(eMetadata); @@ -40,7 +36,7 @@ void VerifyMetadata(EventMetadata eMetdata) Assert.IsTrue(flags.Contains("flag1")); } - private void sdkReady_callback(object sender, EventMetadata metadata) + private void sdkReady_callback(EventMetadata metadata) { SdkReady = true; eMetadata = metadata; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 3c1a25d9..50c3ee78 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -9,14 +9,14 @@ namespace Splitio_Tests.Unit_Tests.Common [TestClass] public class EventsManagerTests { - private bool SdkReady = false; - private bool SdkReady2 = false; - private bool SdkTimedOut = false; - private bool SdkUpdate = false; + private bool SdkReadyFlag = false; + private bool SdkReadyFlag2 = false; + private bool SdkTimedOutFlag = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; + public event EventHandler SdkReady; + public event EventHandler SdkUpdate; + public event EventHandler SdkTimedOut; [TestMethod] public void TestFiringEvents() @@ -25,107 +25,107 @@ public void TestFiringEvents() EventsManagerConfig config = new EventsManagerConfig(); EventsManager eventsManager = new EventsManager(config); - PublicSdkReadyHandler += sdkReady_callback; - PublicSdkReadyHandler += sdkReady_callback2; - PublicSdkUpdateHandler += sdkUpdate_callback; - PublicSdkTimedOutHandler += sdkTimedOut_callback; + SdkReady += sdkReady_callback; + SdkReady += sdkReady_callback2; + SdkUpdate += sdkUpdate_callback; + SdkTimedOut += sdkTimedOut_callback; Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventsManager.Register(SdkEvent.SdkReady, PublicSdkReadyHandler); - eventsManager.Register(SdkEvent.SdkUpdate, PublicSdkUpdateHandler); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); // not fired as it is not registered yet - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsTrue(SdkTimedOut); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsTrue(SdkTimedOutFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkReady); - Assert.IsTrue(SdkReady2); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); + System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsTrue(SdkReadyFlag); + Assert.IsTrue(SdkReadyFlag2); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); // not fired as suppressed by sdkReady ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); eventsManager.Unregister(SdkEvent.SdkUpdate); eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); } void ResetAllVariables() { - SdkReady = false; - SdkReady2 = false; - SdkTimedOut = false; + SdkReadyFlag = false; + SdkReadyFlag2 = false; + SdkTimedOutFlag = false; eMetadata = null; - SdkUpdate = false; + SdkUpdateFlag = false; } void VerifyMetadata(EventMetadata eMetdata) @@ -138,26 +138,42 @@ void VerifyMetadata(EventMetadata eMetdata) private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } private void sdkReady_callback(object sender, EventMetadata metadata) { - SdkReady = true; + SdkReadyFlag = true; eMetadata = metadata; } private void sdkReady_callback2(object sender, EventMetadata metadata) { - SdkReady2 = true; + SdkReadyFlag2 = true; eMetadata = metadata; } private void sdkTimedOut_callback(object sender, EventMetadata metadata) { - SdkTimedOut = true; + SdkTimedOutFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } + + private void TriggerSdkTimeout(EventMetadata metaData) + { + SdkTimedOut?.Invoke(this, metaData); + } + } } diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index 120072f3..65f1757d 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -12,9 +12,9 @@ namespace Splitio_Tests.Unit_Tests.Shared [TestClass] public class SelfRefreshingBlockUntilReadyServiceTests { - private bool SdkTimedOut = false; + private bool SdkTimedOutFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkTimedOut; [TestMethod] public void TestFireTimedOutEvent() @@ -24,8 +24,8 @@ public void TestFireTimedOutEvent() Mock telemetryProducer = new Mock(); EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, eventsManager); - PublicSdkUpdateHandler += SdkTimedOut_callback; - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkUpdateHandler); + SdkTimedOut += sdkTimeout_callback; + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimedOut); statusManager .Setup(mock => mock.WaitUntilReady(1)) .Returns(false); @@ -38,14 +38,19 @@ public void TestFireTimedOutEvent() catch { } // Assert. - Assert.IsTrue(SdkTimedOut); + Assert.IsTrue(SdkTimedOutFlag); Assert.AreEqual(0, eMetadata.GetData().Count); } - private void SdkTimedOut_callback(object sender, EventMetadata metadata) + private void sdkTimeout_callback(object sender, EventMetadata metadata) { - SdkTimedOut = true; + SdkTimedOutFlag = true; eMetadata = metadata; } + + private void TriggerSdkTimedOut(EventMetadata metaData) + { + SdkTimedOut?.Invoke(this, metaData); + } } } From 26a78f83e9ba8aea355471f0dfe1d86ec9e9649e Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 12:35:11 -0800 Subject: [PATCH 53/87] polish --- src/Splitio/Services/Common/EventDelivery.cs | 3 +-- src/Splitio/Services/Common/EventsManager.cs | 13 +++++++------ src/Splitio/Services/Common/IEventDelivery.cs | 3 +-- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 38b04ffe..288cb018 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,5 +1,4 @@ -using Splitio.Domain; -using Splitio.Services.Logger; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index d891e883..483368b1 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -186,8 +186,8 @@ private List CheckRequireAll() private bool CheckPrerequisites(E sdkEvent) { - foreach (var item in _managerConfig.Prerequisites.Where(kvp => kvp.Key.Equals(sdkEvent) && - kvp.Value.Any(x => !EventAlreadyTriggered(x)))) + if (_managerConfig.Prerequisites.Where(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => !EventAlreadyTriggered(x))).Count() > 0) { return false; } @@ -197,8 +197,8 @@ private bool CheckPrerequisites(E sdkEvent) private bool CheckSuppressedBy(E sdkEvent) { - foreach (var item in _managerConfig.SuppressedBy.Where(kvp => kvp.Key.Equals(sdkEvent) && - kvp.Value.Any(x => EventAlreadyTriggered(x)))) + if (_managerConfig.SuppressedBy.Where(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => EventAlreadyTriggered(x))).Count() > 0) { return false; } @@ -222,10 +222,11 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) Valid = false }; - foreach (var item in _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent))) + var sdkEvent = _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent)); + if (sdkEvent.Count() > 0) { validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = item.Key; + validSdkEvent.SdkEvent = sdkEvent.First().Key; return validSdkEvent; } diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs index 69ae709f..83bb4540 100644 --- a/src/Splitio/Services/Common/IEventDelivery.cs +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -1,5 +1,4 @@ -using Splitio.Domain; -using System; +using System; namespace Splitio.Services.Common { From 9415ac1c4332aab815f769856e39d62ef5b22dcc Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 13:22:13 -0800 Subject: [PATCH 54/87] polish --- src/Splitio/Services/Common/EventsManager.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 483368b1..f50e0e81 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -24,7 +24,7 @@ private struct PublicEventProperties private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - public readonly EventDelivery _eventDelivery; + private readonly EventDelivery _eventDelivery; private readonly object _lock = new object(); public EventManagerConfigData _managerConfig { get; private set; } @@ -186,8 +186,8 @@ private List CheckRequireAll() private bool CheckPrerequisites(E sdkEvent) { - if (_managerConfig.Prerequisites.Where(kvp => kvp.Key.Equals(sdkEvent) && - kvp.Value.Any(x => !EventAlreadyTriggered(x))).Count() > 0) + if (_managerConfig.Prerequisites.Any(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => !EventAlreadyTriggered(x)))) { return false; } @@ -197,8 +197,8 @@ private bool CheckPrerequisites(E sdkEvent) private bool CheckSuppressedBy(E sdkEvent) { - if (_managerConfig.SuppressedBy.Where(kvp => kvp.Key.Equals(sdkEvent) && - kvp.Value.Any(x => EventAlreadyTriggered(x))).Count() > 0) + if (_managerConfig.SuppressedBy.Any(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => EventAlreadyTriggered(x)))) { return false; } @@ -208,10 +208,11 @@ private bool CheckSuppressedBy(E sdkEvent) private int ExecutionLimit(E sdkEvent) { - if (!_managerConfig.ExecutionLimits.ContainsKey(sdkEvent)) + if (!_managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit)) + { return -1; + } - _managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); return limit; } @@ -223,7 +224,7 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) }; var sdkEvent = _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent)); - if (sdkEvent.Count() > 0) + if (sdkEvent.Any()) { validSdkEvent.Valid = true; validSdkEvent.SdkEvent = sdkEvent.First().Key; From a1d89a9dab936c59ef23785cf899fce6b54c0b24 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 14:16:52 -0800 Subject: [PATCH 55/87] passed EventDelivery as a param to EventsManager --- .../Services/Client/Classes/JSONFileClient.cs | 2 +- .../Client/Classes/LocalhostClient.cs | 2 +- .../Client/Classes/SelfRefreshingClient.cs | 2 +- src/Splitio/Services/Common/EventsManager.cs | 6 +-- .../SelfRefreshingSegmentFetcherTests.cs | 2 +- .../TargetingRulesFetcherTests.cs | 6 +-- .../InMemory/RuleBasedSegmentCacheTests.cs | 3 +- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 2 +- .../Cache/InMemory/SegmentCacheTests.cs | 23 +++++------ .../Cache/InMemory/SplitCacheAsyncTests.cs | 3 +- .../Cache/InMemory/SplitCacheTests.cs | 38 +++++++++--------- .../Unit Tests/Common/EventsManagerTests.cs | 2 +- .../UserDefinedSegmentMatcherAsyncTests.cs | 33 ++++++++-------- .../UserDefinedSegmentMatcherTests.cs | 39 ++++++++++--------- .../SelfRefreshingSegmentFetcherUnitTests.cs | 4 +- .../SelfRefreshingSegmentUnitTests.cs | 8 ++-- 16 files changed, 88 insertions(+), 87 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index 371c84f4..ec5a40aa 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -35,7 +35,7 @@ public JSONFileClient(string splitsFilePath, IRuleBasedSegmentCache ruleBasedSegmentCache = null ) : base("localhost", fallbackTreatmentCalculator) { - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index 1afea359..e42fca1e 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -47,7 +47,7 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm BuildFlagSetsFilter(new HashSet()); - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var splits = _localhostFileService.ParseSplitFile(_fullPath); _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, eventsManager); diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 33141a74..370e6a2b 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -92,7 +92,7 @@ public SelfRefreshingClient(string apiKey, ConfigurationOptions config, #region Private Methods private void BuildEventsManager() { - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); } private void BuildSplitCache() { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index f50e0e81..bda64bd6 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -24,15 +24,15 @@ private struct PublicEventProperties private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - private readonly EventDelivery _eventDelivery; + private readonly IEventDelivery _eventDelivery; private readonly object _lock = new object(); public EventManagerConfigData _managerConfig { get; private set; } - public EventsManager(EventManagerConfigData eventsManagerConfig) + public EventsManager(EventManagerConfigData eventsManagerConfig, IEventDelivery eventDelivery) { _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); - _eventDelivery = new EventDelivery(); + _eventDelivery = eventDelivery; _managerConfig = eventsManagerConfig; } diff --git a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs index bde1a569..70839600 100644 --- a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs @@ -27,7 +27,7 @@ public SelfRefreshingSegmentFetcherTests() public void ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index f2b7dfe7..c949489c 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -38,7 +38,7 @@ public TargetingRulesFetcherTests() public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); @@ -84,7 +84,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAllocation() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); @@ -142,7 +142,7 @@ public async Task ExecuteGetWithoutResults() var sdkSegmentApiClient = new SegmentSdkApiClient(httpClient, telemetryStorage, baseUrl); var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); var gates = new InMemoryReadinessGatesCache(); - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index b43c27ca..023b5ce8 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -23,7 +23,7 @@ public class RuleBasedSegmentCacheTests public void Setup() { var cache = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _segmentCache = new InMemoryRuleBasedSegmentCache(cache, _eventsManager); } @@ -155,7 +155,6 @@ public void Contains_ShouldReturnTrue() public void Update_ShouldNotifyEvent() { // Arrange - var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index 64ff38f3..dcaf47d0 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -23,7 +23,7 @@ public class SegmentCacheAsyncTests public SegmentCacheAsyncTests() { var segments = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _cache = new InMemorySegmentCache(segments, _eventsManager); } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index 235d9408..689d109b 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; @@ -20,8 +21,8 @@ public class SegmentCacheTests public void RegisterSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "abcd", "1234" }; var segmentName = "test"; @@ -37,8 +38,8 @@ public void RegisterSegmentTest() public void IsNotInSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -54,8 +55,8 @@ public void IsNotInSegmentTest() public void IsInSegmentWithInexistentSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); //Act var result = segmentCache.IsInSegment("test", "abcd"); @@ -68,8 +69,8 @@ public void IsInSegmentWithInexistentSegmentTest() public void RemoveKeyFromSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -88,8 +89,8 @@ public void RemoveKeyFromSegmentTest() public void SetAndGetChangeNumberTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var segmentName = "test"; //Act @@ -105,7 +106,7 @@ public void SetAndGetChangeNumberTest() public void NotifyEventsTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index c02d905f..985b6275 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -27,8 +27,7 @@ public SplitCacheAsyncTests() { _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); - + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 33a0889d..651f66ee 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -29,8 +29,8 @@ public SplitCacheTests() public void AddAndGetSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -45,8 +45,8 @@ public void AddAndGetSplitTest() public void AddDuplicateSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -66,8 +66,8 @@ public void AddDuplicateSplitTest() public void GetInexistentSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -84,8 +84,8 @@ public void RemoveSplitTest() var splitName = "test1"; var splits = new ConcurrentDictionary(); splits.TryAdd(splitName, new ParsedSplit() { name = splitName }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager.Object); //Act splitCache.Update(new List(), new List { splitName }, -1); @@ -99,8 +99,8 @@ public void RemoveSplitTest() public void SetAndGetChangeNumberTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var changeNumber = 1234; //Act @@ -115,8 +115,8 @@ public void SetAndGetChangeNumberTest() public void GetAllSplitsTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; var splitName2 = "test2"; @@ -135,8 +135,8 @@ public void GetAllSplitsTest() public void AddOrUpdate_WhenUpdateTraffictType_ReturnsTrue() { // Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "split_1"; var splitName2 = "split_2"; @@ -178,8 +178,8 @@ public void GetNamesByFlagSetsWithoutFilter() Sets = new HashSet { "set1", "set2" } }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -222,8 +222,8 @@ public void GetNamesByFlagSetsWithFilters() defaultTreatment = "on", Sets = new HashSet { "set1", "set2" } }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -245,7 +245,7 @@ public void GetNamesByFlagSetsWithFilters() public void NotifyUpdateEventTest() { // Arrange. - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 50c3ee78..5d662d98 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -23,7 +23,7 @@ public void TestFiringEvents() { //Act EventsManagerConfig config = new EventsManagerConfig(); - EventsManager eventsManager = new EventsManager(config); + EventsManager eventsManager = new EventsManager(config, new EventDelivery()); SdkReady += sdkReady_callback; SdkReady += sdkReady_callback2; diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs index e870361b..f3a0ff0e 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; @@ -23,8 +24,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -47,8 +48,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -65,8 +66,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -83,8 +84,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -106,8 +107,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -130,8 +131,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -148,8 +149,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -166,8 +167,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs index 11239973..f7c1245c 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs @@ -1,10 +1,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Splitio.Services.Parsing; +using Moq; using Splitio.Domain; -using System.Collections.Generic; -using System.Collections.Concurrent; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; +using Splitio.Services.Parsing; +using System.Collections.Concurrent; +using System.Collections.Generic; namespace Splitio_Tests.Unit_Tests { @@ -22,8 +23,8 @@ public void MatchShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -46,8 +47,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -64,8 +65,8 @@ public void MatchShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -82,8 +83,8 @@ public void MatchShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -105,8 +106,8 @@ public void MatchShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -129,8 +130,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -147,8 +148,8 @@ public void MatchShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -165,8 +166,8 @@ public void MatchShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 9e242cc8..e16e8ca3 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -32,8 +32,8 @@ public void InitializeSegmentNotExistent() var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(5, segmentsQueue); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs index 06f32feb..83074558 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs @@ -23,8 +23,8 @@ public async Task FetchSegmentNullChangesFetcherResponseShouldNotUpdateCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient @@ -46,8 +46,8 @@ public async Task FetchSegmentShouldUpdateSegmentsCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient From c0d0b87d95860b74da2c2b360a524851561619a9 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 16:09:57 -0800 Subject: [PATCH 56/87] add EventDelivery as a paramater to EventsManager --- .../Services/Client/Classes/SplitClient.cs | 19 +++++++++ .../Services/Client/Classes/SplitFactory.cs | 2 +- src/Splitio/Services/Common/EventsManager.cs | 20 +++++----- .../BaseLocalhostClientTests.cs | 2 +- .../Integration Tests/InMemoryClientTests.cs | 2 +- .../Integration Tests/JSONFileClientTests.cs | 2 +- .../Integration Tests/RedisClientTests.cs | 2 +- .../SelfRefreshingSegmentFetcherTests.cs | 2 +- .../TargetingRulesFetcherTests.cs | 6 +-- .../InMemory/RuleBasedSegmentCacheTests.cs | 3 +- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 2 +- .../Cache/InMemory/SegmentCacheTests.cs | 23 +++++------ .../Cache/InMemory/SplitCacheAsyncTests.cs | 3 +- .../Cache/InMemory/SplitCacheTests.cs | 38 +++++++++--------- .../Client/LocalhostClientForTesting.cs | 2 +- .../Client/LocalhostClientUnitTests.cs | 2 +- .../Client/SdkReadinessGatesUnitTests.cs | 4 +- .../Client/SplitClientForTesting.cs | 2 +- .../Unit Tests/Common/EventsManagerTests.cs | 2 +- .../Impressions/ImpressionsCounterTests.cs | 2 +- .../UserDefinedSegmentMatcherAsyncTests.cs | 33 ++++++++-------- .../UserDefinedSegmentMatcherTests.cs | 39 ++++++++++--------- .../SelfRefreshingSegmentFetcherUnitTests.cs | 7 ++-- .../SelfRefreshingSegmentUnitTests.cs | 8 ++-- ...lfRefreshingBlockUntilReadyServiceTests.cs | 2 +- .../EventSourceClientTests.cs | 2 +- .../StreamingClientTests.cs | 22 +++++++++-- .../Splitio.TestSupport/SplitClientForTest.cs | 2 +- 28 files changed, 146 insertions(+), 109 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 6e9465c0..801e416b 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -73,6 +73,10 @@ protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatme { ApiKey = apikey; _eventsManager = eventsManager; + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReadyEvent); + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdateEvent); + _eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeoutEvent); + _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _wrapperAdapter = WrapperAdapter.Instance(); _keyValidator = new KeyValidator(); @@ -574,6 +578,21 @@ private static SplitResult TreatmentWithConfig(List results) return new SplitResult(result.Treatment, result.Config); } + + private void TriggerSdkReadyEvent(EventMetadata metadata) + { + SdkReady?.Invoke(this, metadata); + } + + private void TriggerSdkUpdateEvent(EventMetadata metadata) + { + SdkUpdate?.Invoke(this, metadata); + } + + private void TriggerSdkTimeoutEvent(EventMetadata metadata) + { + SdkTimedOut?.Invoke(this, metadata); + } #endregion } } \ No newline at end of file diff --git a/src/Splitio/Services/Client/Classes/SplitFactory.cs b/src/Splitio/Services/Client/Classes/SplitFactory.cs index d22b6647..27742c36 100644 --- a/src/Splitio/Services/Client/Classes/SplitFactory.cs +++ b/src/Splitio/Services/Client/Classes/SplitFactory.cs @@ -60,7 +60,7 @@ public ISplitManager Manager() private void BuildSplitClient() { FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(_options.FallbackTreatments); - EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); switch (_options.Mode) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index d891e883..bda64bd6 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -24,15 +24,15 @@ private struct PublicEventProperties private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - public readonly EventDelivery _eventDelivery; + private readonly IEventDelivery _eventDelivery; private readonly object _lock = new object(); public EventManagerConfigData _managerConfig { get; private set; } - public EventsManager(EventManagerConfigData eventsManagerConfig) + public EventsManager(EventManagerConfigData eventsManagerConfig, IEventDelivery eventDelivery) { _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); - _eventDelivery = new EventDelivery(); + _eventDelivery = eventDelivery; _managerConfig = eventsManagerConfig; } @@ -186,7 +186,7 @@ private List CheckRequireAll() private bool CheckPrerequisites(E sdkEvent) { - foreach (var item in _managerConfig.Prerequisites.Where(kvp => kvp.Key.Equals(sdkEvent) && + if (_managerConfig.Prerequisites.Any(kvp => kvp.Key.Equals(sdkEvent) && kvp.Value.Any(x => !EventAlreadyTriggered(x)))) { return false; @@ -197,7 +197,7 @@ private bool CheckPrerequisites(E sdkEvent) private bool CheckSuppressedBy(E sdkEvent) { - foreach (var item in _managerConfig.SuppressedBy.Where(kvp => kvp.Key.Equals(sdkEvent) && + if (_managerConfig.SuppressedBy.Any(kvp => kvp.Key.Equals(sdkEvent) && kvp.Value.Any(x => EventAlreadyTriggered(x)))) { return false; @@ -208,10 +208,11 @@ private bool CheckSuppressedBy(E sdkEvent) private int ExecutionLimit(E sdkEvent) { - if (!_managerConfig.ExecutionLimits.ContainsKey(sdkEvent)) + if (!_managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit)) + { return -1; + } - _managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); return limit; } @@ -222,10 +223,11 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) Valid = false }; - foreach (var item in _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent))) + var sdkEvent = _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent)); + if (sdkEvent.Any()) { validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = item.Key; + validSdkEvent.SdkEvent = sdkEvent.First().Key; return validSdkEvent; } diff --git a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs index fe9b3227..9bb56c7f 100644 --- a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs @@ -33,7 +33,7 @@ public BaseLocalhostClientTests(string mode) rootFilePath = string.Empty; _mode = mode; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs index 2279838c..e16d7f0f 100644 --- a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs @@ -20,7 +20,7 @@ public InMemoryClientTests() // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs index 6bdc8e55..c4868dea 100644 --- a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs @@ -27,7 +27,7 @@ public JSONFileClientTests() // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs index 8ad5f8be..f600179a 100644 --- a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs @@ -40,7 +40,7 @@ public void Initialization() UserPrefix = _prefix }; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); config = new ConfigurationOptions { CacheAdapterConfig = cacheAdapterConfig, diff --git a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs index bde1a569..70839600 100644 --- a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs @@ -27,7 +27,7 @@ public SelfRefreshingSegmentFetcherTests() public void ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index e6049299..7d4e8f53 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -38,7 +38,7 @@ public TargetingRulesFetcherTests() public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); @@ -84,7 +84,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAllocation() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); @@ -141,7 +141,7 @@ public async Task ExecuteGetWithoutResults() var apiSplitChangeFetcher = new ApiSplitChangeFetcher(sdkApiClient); var sdkSegmentApiClient = new SegmentSdkApiClient(httpClient, telemetryStorage, baseUrl); var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var gates = new InMemoryReadinessGatesCache(eventsManager); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentsQueue = new SplitQueue(); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index b43c27ca..023b5ce8 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -23,7 +23,7 @@ public class RuleBasedSegmentCacheTests public void Setup() { var cache = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _segmentCache = new InMemoryRuleBasedSegmentCache(cache, _eventsManager); } @@ -155,7 +155,6 @@ public void Contains_ShouldReturnTrue() public void Update_ShouldNotifyEvent() { // Arrange - var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index 64ff38f3..dcaf47d0 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -23,7 +23,7 @@ public class SegmentCacheAsyncTests public SegmentCacheAsyncTests() { var segments = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _cache = new InMemorySegmentCache(segments, _eventsManager); } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index 235d9408..689d109b 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; @@ -20,8 +21,8 @@ public class SegmentCacheTests public void RegisterSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "abcd", "1234" }; var segmentName = "test"; @@ -37,8 +38,8 @@ public void RegisterSegmentTest() public void IsNotInSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -54,8 +55,8 @@ public void IsNotInSegmentTest() public void IsInSegmentWithInexistentSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); //Act var result = segmentCache.IsInSegment("test", "abcd"); @@ -68,8 +69,8 @@ public void IsInSegmentWithInexistentSegmentTest() public void RemoveKeyFromSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -88,8 +89,8 @@ public void RemoveKeyFromSegmentTest() public void SetAndGetChangeNumberTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var segmentName = "test"; //Act @@ -105,7 +106,7 @@ public void SetAndGetChangeNumberTest() public void NotifyEventsTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index c02d905f..985b6275 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -27,8 +27,7 @@ public SplitCacheAsyncTests() { _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); - + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 33a0889d..651f66ee 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -29,8 +29,8 @@ public SplitCacheTests() public void AddAndGetSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -45,8 +45,8 @@ public void AddAndGetSplitTest() public void AddDuplicateSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -66,8 +66,8 @@ public void AddDuplicateSplitTest() public void GetInexistentSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -84,8 +84,8 @@ public void RemoveSplitTest() var splitName = "test1"; var splits = new ConcurrentDictionary(); splits.TryAdd(splitName, new ParsedSplit() { name = splitName }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager.Object); //Act splitCache.Update(new List(), new List { splitName }, -1); @@ -99,8 +99,8 @@ public void RemoveSplitTest() public void SetAndGetChangeNumberTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var changeNumber = 1234; //Act @@ -115,8 +115,8 @@ public void SetAndGetChangeNumberTest() public void GetAllSplitsTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; var splitName2 = "test2"; @@ -135,8 +135,8 @@ public void GetAllSplitsTest() public void AddOrUpdate_WhenUpdateTraffictType_ReturnsTrue() { // Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "split_1"; var splitName2 = "split_2"; @@ -178,8 +178,8 @@ public void GetNamesByFlagSetsWithoutFilter() Sets = new HashSet { "set1", "set2" } }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -222,8 +222,8 @@ public void GetNamesByFlagSetsWithFilters() defaultTreatment = "on", Sets = new HashSet { "set1", "set2" } }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -245,7 +245,7 @@ public void GetNamesByFlagSetsWithFilters() public void NotifyUpdateEventTest() { // Arrange. - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs index b97cff0e..deb27c04 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs @@ -7,7 +7,7 @@ namespace Splitio_Tests.Unit_Tests.Client { public class LocalhostClientForTesting : LocalhostClient { - public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig())) + public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig(), new EventDelivery())) { } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs index 05f826be..7bdfe24a 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs @@ -21,7 +21,7 @@ public LocalhostClientUnitTests() // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index c53d5252..d17713b5 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -17,7 +17,7 @@ public class InMemoryReadinessGatesCacheUnitTests public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() { //Arrange - var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); //Act var result = gates.IsReady(); @@ -30,7 +30,7 @@ public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() public void TestFireReadyEvent() { //Arrange - EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var gates = new InMemoryReadinessGatesCache(eventsManager); SdkReady += sdkReady_callback; eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs index 12277bcb..a44f94eb 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs @@ -23,7 +23,7 @@ public SplitClientForTesting(IFeatureFlagCacheConsumer featureFlagCacheConsumer, ISyncManager syncManager, FallbackTreatmentCalculator fallbackTreatmentCalculator, ITelemetryEvaluationProducer telemetryEvaluationProducer) - : base("SplitClientForTesting", fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig())) + : base("SplitClientForTesting", fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig(), new EventDelivery())) { _eventsLog = eventsLog; _impressionsLog = impressionsLog; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 50c3ee78..5d662d98 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -23,7 +23,7 @@ public void TestFiringEvents() { //Act EventsManagerConfig config = new EventsManagerConfig(); - EventsManager eventsManager = new EventsManager(config); + EventsManager eventsManager = new EventsManager(config, new EventDelivery()); SdkReady += sdkReady_callback; SdkReady += sdkReady_callback2; diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index 42df730c..049312b8 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -29,7 +29,7 @@ public void Start_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs index e870361b..f3a0ff0e 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; @@ -23,8 +24,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -47,8 +48,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -65,8 +66,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -83,8 +84,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -106,8 +107,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -130,8 +131,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -148,8 +149,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -166,8 +167,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs index 11239973..f7c1245c 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs @@ -1,10 +1,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Splitio.Services.Parsing; +using Moq; using Splitio.Domain; -using System.Collections.Generic; -using System.Collections.Concurrent; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; +using Splitio.Services.Parsing; +using System.Collections.Concurrent; +using System.Collections.Generic; namespace Splitio_Tests.Unit_Tests { @@ -22,8 +23,8 @@ public void MatchShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -46,8 +47,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -64,8 +65,8 @@ public void MatchShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -82,8 +83,8 @@ public void MatchShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -105,8 +106,8 @@ public void MatchShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -129,8 +130,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -147,8 +148,8 @@ public void MatchShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -165,8 +166,8 @@ public void MatchShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 97a68959..8e7110ca 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -8,7 +8,6 @@ using Splitio.Services.SegmentFetcher.Classes; using Splitio.Services.SegmentFetcher.Interfaces; using Splitio.Services.Shared.Classes; -using Splitio.Services.Shared.Interfaces; using Splitio.Services.SplitFetcher.Interfaces; using Splitio.Services.Tasks; using System.Collections.Concurrent; @@ -27,13 +26,13 @@ public class SelfRefreshingSegmentFetcherUnitTests public void InitializeSegmentNotExistent() { // Arrange - var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var gates = new InMemoryReadinessGatesCache(new Mock>().Object); gates.SetReady(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(5, segmentsQueue); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs index 06f32feb..83074558 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs @@ -23,8 +23,8 @@ public async Task FetchSegmentNullChangesFetcherResponseShouldNotUpdateCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient @@ -46,8 +46,8 @@ public async Task FetchSegmentShouldUpdateSegmentsCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index 65f1757d..6f63501d 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -22,7 +22,7 @@ public void TestFireTimedOutEvent() //Arrange Mock statusManager = new Mock(); Mock telemetryProducer = new Mock(); - EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, eventsManager); SdkTimedOut += sdkTimeout_callback; eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimedOut); diff --git a/tests/Splitio.Integration-tests/EventSourceClientTests.cs b/tests/Splitio.Integration-tests/EventSourceClientTests.cs index 0eb26bdd..b7850c78 100644 --- a/tests/Splitio.Integration-tests/EventSourceClientTests.cs +++ b/tests/Splitio.Integration-tests/EventSourceClientTests.cs @@ -370,7 +370,7 @@ private static (IEventSourceClient, BlockingCollection, var sseHttpClient = new SplitioHttpClient("api-key", config, new Dictionary()); var telemetryRuntimeProducer = new InMemoryTelemetryStorage(); var notificationManagerKeeper = new NotificationManagerKeeper(telemetryRuntimeProducer, streamingStatusQueue); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var tasksManager = new TasksManager(statusManager); var task = tasksManager.NewOnTimeTask(Enums.Task.SSEConnect); diff --git a/tests/Splitio.Integration-tests/StreamingClientTests.cs b/tests/Splitio.Integration-tests/StreamingClientTests.cs index 7623dadd..6dab8142 100644 --- a/tests/Splitio.Integration-tests/StreamingClientTests.cs +++ b/tests/Splitio.Integration-tests/StreamingClientTests.cs @@ -22,6 +22,10 @@ namespace Splitio.Integration_tests public class StreamingClientTests { public static string EventSourcePath => "/eventsource"; + private bool SdkReadyFlag = false; + private bool SdkReadyFlag2 = false; + private bool SdkUpdateFlag = false; + private EventMetadata eMetadata; [TestMethod] public void GetTreatment_SplitUpdate_ShouldFetch() @@ -60,14 +64,17 @@ public void GetTreatment_SplitUpdate_ShouldFetch() }; var apikey = "apikey1"; - var splitFactory = new SplitFactory(apikey, config); - var client = splitFactory.Client(); + var client = (SplitClient)splitFactory.Client(); + client.SdkReady += sdkReady_callback; + client.SdkReady += sdkReady_callback2; client.BlockUntilReady(10000); var result = EvaluateWithDelay("admin", "push_test", "after_fetch", client); Assert.AreEqual("after_fetch", result); + Assert.IsTrue(SdkReadyFlag); + Assert.IsTrue(SdkReadyFlag2); client.Destroy(); } @@ -169,7 +176,6 @@ public void GetTreatment_SplitKill_ShouldFetch() Thread.Sleep(5000); var result = client.GetTreatment("admin", "push_test"); - Assert.AreEqual("after_fetch", result); client.Destroy(); @@ -765,5 +771,15 @@ public static string EvaluateWithDelay(string key, string splitName, string expe return result; } + + private void sdkReady_callback(object sender, EventMetadata metadata) + { + SdkReadyFlag = true; + } + + private void sdkReady_callback2(object sender, EventMetadata metadata) + { + SdkReadyFlag2 = true; + } } } diff --git a/tests/Splitio.TestSupport/SplitClientForTest.cs b/tests/Splitio.TestSupport/SplitClientForTest.cs index f79f6674..363380c2 100644 --- a/tests/Splitio.TestSupport/SplitClientForTest.cs +++ b/tests/Splitio.TestSupport/SplitClientForTest.cs @@ -11,7 +11,7 @@ public class SplitClientForTest : SplitClient private readonly Dictionary _tests; public SplitClientForTest() : base("SplitClientForTest", new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()), - new EventsManager(new EventsManagerConfig())) + new EventsManager(new EventsManagerConfig(), new EventDelivery())) { _tests = new Dictionary(); } From 748a6d5376cde4a4b8ebfb5ea1a3a011387a2a57 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 23 Dec 2025 22:14:09 -0800 Subject: [PATCH 57/87] Updated client and integration tests --- .../Classes/InMemoryReadinessGatesCache.cs | 1 + .../Cache/Classes/InMemorySplitCache.cs | 1 + .../Client/Classes/SelfRefreshingClient.cs | 2 +- .../Services/Client/Classes/SplitClient.cs | 56 ++++++- .../Services/Client/Classes/SplitFactory.cs | 2 +- .../Client/Interfaces/ISplitClient.cs | 1 + src/Splitio/Services/Common/EventDelivery.cs | 7 +- src/Splitio/Services/Common/EventsManager.cs | 65 +++----- src/Splitio/Services/Common/IEventDelivery.cs | 2 +- src/Splitio/Services/Common/IEventsManager.cs | 7 +- .../BaseLocalhostClientTests.cs | 2 +- .../Integration Tests/InMemoryClientTests.cs | 2 +- .../Integration Tests/JSONFileClientTests.cs | 2 +- .../Integration Tests/RedisClientTests.cs | 2 +- .../SelfRefreshingSegmentFetcherTests.cs | 2 +- .../TargetingRulesFetcherTests.cs | 6 +- .../InMemory/RuleBasedSegmentCacheTests.cs | 30 ++-- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 29 ++-- .../Cache/InMemory/SegmentCacheTests.cs | 54 ++++--- .../Cache/InMemory/SplitCacheAsyncTests.cs | 34 +++-- .../Cache/InMemory/SplitCacheTests.cs | 69 +++++---- .../Client/LocalhostClientForTesting.cs | 2 +- .../Client/LocalhostClientUnitTests.cs | 2 +- .../Client/SdkReadinessGatesUnitTests.cs | 21 ++- .../Client/SplitClientForTesting.cs | 2 +- .../Unit Tests/Common/EventDeliveryTests.cs | 8 +- .../Unit Tests/Common/EventsManagerTests.cs | 144 ++++++++++-------- .../Impressions/ImpressionsCounterTests.cs | 8 +- .../Impressions/UniqueKeysTrackerTests.cs | 8 +- .../UserDefinedSegmentMatcherAsyncTests.cs | 33 ++-- .../UserDefinedSegmentMatcherTests.cs | 39 ++--- .../SelfRefreshingSegmentFetcherUnitTests.cs | 7 +- .../SelfRefreshingSegmentUnitTests.cs | 8 +- ...lfRefreshingBlockUntilReadyServiceTests.cs | 21 ++- .../EventSourceClientTests.cs | 2 +- .../PollingClientTests.cs | 15 +- .../StreamingClientTests.cs | 40 ++++- .../Splitio.TestSupport/SplitClientForTest.cs | 2 +- 38 files changed, 445 insertions(+), 293 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index f784fbbe..9d4b2e2d 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -30,6 +30,7 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); + Thread.Sleep(1000); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index 73bddb5d..1a99fd8c 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -74,6 +74,7 @@ public void Update(List toAdd, List toRemove, long till) { DecreaseTrafficTypeCount(removedSplit); RemoveFromFlagSets(removedSplit.name, removedSplit.Sets); + eventsFlags.Add(featureFlagName); } } diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 7d513bc5..a455f737 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -55,7 +55,7 @@ public class SelfRefreshingClient : SplitClient public SelfRefreshingClient(string apiKey, ConfigurationOptions config, FallbackTreatmentCalculator fallbackTreatmentCalculator, - IEventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) + EventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) { _config = (SelfRefreshingConfig)_configService.ReadConfig(config, ConfigTypes.InMemory); _fallbackTreatmentCalculator = fallbackTreatmentCalculator; diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index d37ed283..e1f21480 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,16 +63,33 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; - protected IEventsManager _eventsManager; - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; + public IEventsManager _eventsManager; + private EventHandler SdkReadyEvent; + public event EventHandler SdkReady + { + add + { + SdkReadyEvent = (EventHandler)Delegate.Combine(SdkReadyEvent, value); + if (_eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)) + { + SdkReadyEvent.Invoke(this, null); + } + } + + remove + { + SdkReadyEvent = (EventHandler)Delegate.Remove(SdkReadyEvent, value); + } + } + public event EventHandler SdkUpdate; + public event EventHandler SdkTimedOut; protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, IEventsManager eventsManager) { ApiKey = apikey; _eventsManager = eventsManager; + RegisterEvents(); _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _wrapperAdapter = WrapperAdapter.Instance(); @@ -83,7 +100,7 @@ protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatme _factoryInstantiationsService = FactoryInstantiationsService.Instance(); _flagSetsValidator = new FlagSetsValidator(); _configService = new ConfigService(_wrapperAdapter, _flagSetsValidator, new SdkMetadataValidator()); - _statusManager = new InMemoryReadinessGatesCache(eventsManager); + _statusManager = new InMemoryReadinessGatesCache(_eventsManager); _tasksManager = new TasksManager(_statusManager); } @@ -305,6 +322,7 @@ public virtual async Task DestroyAsync() _factoryInstantiationsService.Decrease(ApiKey); _statusManager.SetDestroy(); await _syncManager.ShutdownAsync(); + UnregisterEvents(); _log.Info(Messages.Destroyed); } @@ -318,6 +336,7 @@ public virtual void Destroy() _factoryInstantiationsService.Decrease(ApiKey); _statusManager.SetDestroy(); _syncManager.Shutdown(); + UnregisterEvents(); _log.Info(Messages.Destroyed); } @@ -488,6 +507,18 @@ private async Task TrackImpressionsAsync(List evaluatorResults, #endregion #region Private Methods + private void RegisterEvents() + { + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); + } + private void UnregisterEvents() + { + _eventsManager.Unregister(SdkEvent.SdkReady); + _eventsManager.Unregister(SdkEvent.SdkUpdate); + _eventsManager.Unregister(SdkEvent.SdkReadyTimeout); + } private List GetTreatmentsSync(Enums.API method, Key key, List features, Dictionary attributes = null, EvaluationOptions evaluationOptions = null) { try @@ -575,6 +606,21 @@ private static SplitResult TreatmentWithConfig(List results) return new SplitResult(result.Treatment, result.Config); } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReadyEvent?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } + + private void TriggerSdkTimeout(EventMetadata metaData) + { + SdkTimedOut?.Invoke(this, metaData); + } #endregion } } \ No newline at end of file diff --git a/src/Splitio/Services/Client/Classes/SplitFactory.cs b/src/Splitio/Services/Client/Classes/SplitFactory.cs index d22b6647..27742c36 100644 --- a/src/Splitio/Services/Client/Classes/SplitFactory.cs +++ b/src/Splitio/Services/Client/Classes/SplitFactory.cs @@ -60,7 +60,7 @@ public ISplitManager Manager() private void BuildSplitClient() { FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(_options.FallbackTreatments); - EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); switch (_options.Mode) { diff --git a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs index 60e0b751..e78c290f 100644 --- a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs +++ b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs @@ -1,4 +1,5 @@ using Splitio.Domain; +using System; using System.Collections.Generic; namespace Splitio.Services.Client.Interfaces diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index b97e7a32..38b04ffe 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,4 +1,5 @@ -using Splitio.Services.Logger; +using Splitio.Domain; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; @@ -8,14 +9,14 @@ public class EventDelivery : IEventDelivery { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); - public virtual void Deliver(E sdkEvent, M eventMetadata, EventHandler handler) + public virtual void Deliver(E sdkEvent, M eventMetadata, Action handler) { if (handler != null) { _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { - handler.Invoke(this, eventMetadata); + handler.Invoke(eventMetadata); } catch (Exception e) { diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 79ad8373..bda64bd6 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -19,25 +19,25 @@ public struct ValidSdkEvent private struct PublicEventProperties { public bool Triggered; - public EventHandler EventHandler; + public Action EventHandler; } private readonly ConcurrentDictionary _activeSubscriptions; private readonly ConcurrentDictionary _internalEventsStatus; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventsManager"); - private readonly EventDelivery _eventDelivery; + private readonly IEventDelivery _eventDelivery; private readonly object _lock = new object(); public EventManagerConfigData _managerConfig { get; private set; } - public EventsManager(EventManagerConfigData eventsManagerConfig) + public EventsManager(EventManagerConfigData eventsManagerConfig, IEventDelivery eventDelivery) { _activeSubscriptions = new ConcurrentDictionary(); _internalEventsStatus = new ConcurrentDictionary(); - _eventDelivery = new EventDelivery(); + _eventDelivery = eventDelivery; _managerConfig = eventsManagerConfig; } #region Public Methods - public void Register(E sdkEvent, EventHandler handler) + public void Register(E sdkEvent, Action handler) { if (_activeSubscriptions.TryGetValue(sdkEvent, out var _)) { @@ -116,7 +116,7 @@ private void SetSdkEventTriggered(E sdkEvent) _activeSubscriptions.TryUpdate(sdkEvent, newEventData, eventData); } - private EventHandler GetEventHandler(E sdkEvent) + private Action GetEventHandler(E sdkEvent) { if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) { @@ -131,7 +131,6 @@ public List GetSdkEventIfApplicable(I sdkInternalEvent) ValidSdkEvent finalSdkEvent = new ValidSdkEvent { Valid = false -// SdkEvent = SdkEvent.SdkReady }; UpdateSdkInternalEventStatus(sdkInternalEvent, true); List eventsToFire = new List(); @@ -147,11 +146,11 @@ public List GetSdkEventIfApplicable(I sdkInternalEvent) finalSdkEvent.Valid = CheckPrerequisites(finalSdkEvent.SdkEvent) && CheckSuppressedBy(finalSdkEvent.SdkEvent); - } - if (finalSdkEvent.Valid) - { - eventsToFire.Add(finalSdkEvent.SdkEvent); + if (finalSdkEvent.Valid) + { + eventsToFire.Add(finalSdkEvent.SdkEvent); + } } foreach (E sdkEvent in CheckRequireAll()) @@ -187,17 +186,10 @@ private List CheckRequireAll() private bool CheckPrerequisites(E sdkEvent) { - foreach (KeyValuePair> kvp in _managerConfig.Prerequisites) + if (_managerConfig.Prerequisites.Any(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => !EventAlreadyTriggered(x)))) { - if (kvp.Key.Equals(sdkEvent)) - { - if (kvp.Value.Any(x => !EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return false; } return true; @@ -205,17 +197,10 @@ private bool CheckPrerequisites(E sdkEvent) private bool CheckSuppressedBy(E sdkEvent) { - foreach (KeyValuePair> kvp in _managerConfig.SuppressedBy) + if (_managerConfig.SuppressedBy.Any(kvp => kvp.Key.Equals(sdkEvent) && + kvp.Value.Any(x => EventAlreadyTriggered(x)))) { - if (kvp.Key.Equals(sdkEvent)) - { - if (kvp.Value.Any(x => EventAlreadyTriggered(x))) - { - return false; - } - - return true; - } + return false; } return true; @@ -223,10 +208,11 @@ private bool CheckSuppressedBy(E sdkEvent) private int ExecutionLimit(E sdkEvent) { - if (!_managerConfig.ExecutionLimits.ContainsKey(sdkEvent)) + if (!_managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit)) + { return -1; + } - _managerConfig.ExecutionLimits.TryGetValue(sdkEvent, out int limit); return limit; } @@ -235,17 +221,14 @@ private ValidSdkEvent CheckRequireAny(I sdkInternalEvent) ValidSdkEvent validSdkEvent = new ValidSdkEvent { Valid = false -// SdkEvent = SdkEvent.SdkUpdate }; - foreach (KeyValuePair> kvp in _managerConfig.RequireAny) + var sdkEvent = _managerConfig.RequireAny.Where(kvp => kvp.Value.Contains(sdkInternalEvent)); + if (sdkEvent.Any()) { - if (kvp.Value.Contains(sdkInternalEvent)) - { - validSdkEvent.Valid = true; - validSdkEvent.SdkEvent = kvp.Key; - return validSdkEvent; - } + validSdkEvent.Valid = true; + validSdkEvent.SdkEvent = sdkEvent.First().Key; + return validSdkEvent; } return validSdkEvent; diff --git a/src/Splitio/Services/Common/IEventDelivery.cs b/src/Splitio/Services/Common/IEventDelivery.cs index 550cfbbf..69ae709f 100644 --- a/src/Splitio/Services/Common/IEventDelivery.cs +++ b/src/Splitio/Services/Common/IEventDelivery.cs @@ -5,6 +5,6 @@ namespace Splitio.Services.Common { public interface IEventDelivery { - void Deliver(E sdkEvent, M eventMetadata, EventHandler handler); + void Deliver(E sdkEvent, M eventMetadata, Action handler); } } diff --git a/src/Splitio/Services/Common/IEventsManager.cs b/src/Splitio/Services/Common/IEventsManager.cs index 23e719c7..ac5f3739 100644 --- a/src/Splitio/Services/Common/IEventsManager.cs +++ b/src/Splitio/Services/Common/IEventsManager.cs @@ -1,13 +1,12 @@ -using Splitio.Domain; -using System; -using System.Collections.Generic; +using System; namespace Splitio.Services.Common { public interface IEventsManager { void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata); - void Register(E sdkEvent, EventHandler handler); + void Register(E sdkEvent, Action handler); void Unregister(E sdkEvent); + bool EventAlreadyTriggered(E sdkEvent); } } diff --git a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs index fe9b3227..9bb56c7f 100644 --- a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs @@ -33,7 +33,7 @@ public BaseLocalhostClientTests(string mode) rootFilePath = string.Empty; _mode = mode; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs index 2279838c..e16d7f0f 100644 --- a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs @@ -20,7 +20,7 @@ public InMemoryClientTests() // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs index 6bdc8e55..c4868dea 100644 --- a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs @@ -27,7 +27,7 @@ public JSONFileClientTests() // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs index 8ad5f8be..f600179a 100644 --- a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs @@ -40,7 +40,7 @@ public void Initialization() UserPrefix = _prefix }; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); config = new ConfigurationOptions { CacheAdapterConfig = cacheAdapterConfig, diff --git a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs index bde1a569..70839600 100644 --- a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs @@ -27,7 +27,7 @@ public SelfRefreshingSegmentFetcherTests() public void ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index e6049299..7d4e8f53 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -38,7 +38,7 @@ public TargetingRulesFetcherTests() public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); @@ -84,7 +84,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAllocation() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); @@ -141,7 +141,7 @@ public async Task ExecuteGetWithoutResults() var apiSplitChangeFetcher = new ApiSplitChangeFetcher(sdkApiClient); var sdkSegmentApiClient = new SegmentSdkApiClient(httpClient, telemetryStorage, baseUrl); var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var gates = new InMemoryReadinessGatesCache(eventsManager); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var segmentsQueue = new SplitQueue(); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index d4f207c5..023b5ce8 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -14,15 +14,16 @@ public class RuleBasedSegmentCacheTests { private InMemoryRuleBasedSegmentCache _segmentCache; private EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; [TestInitialize] public void Setup() { var cache = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _segmentCache = new InMemoryRuleBasedSegmentCache(cache, _eventsManager); } @@ -154,22 +155,21 @@ public void Contains_ShouldReturnTrue() public void Update_ShouldNotifyEvent() { // Arrange - var segmentToAdd = new RuleBasedSegment { Name = "segment-to-add" }; var segmentToRemove = new RuleBasedSegment { Name = "segment-to-remove" }; var till = 67890; var toNotify = new List { { "segment-to-add" }, { "segment-to-remove" } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act - SdkUpdate = false; + SdkUpdateFlag = false; _segmentCache.Update(new List { segmentToAdd, segmentToRemove }, new List { segmentToRemove.Name }, till); // Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; Assert.IsTrue(rbsegments.Count == 3); @@ -179,8 +179,18 @@ public void Update_ShouldNotifyEvent() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index d44a7343..dcaf47d0 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -15,14 +15,15 @@ public class SegmentCacheAsyncTests { private readonly ISegmentCache _cache; private EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SegmentCacheAsyncTests() { var segments = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _cache = new InMemorySegmentCache(segments, _eventsManager); } @@ -60,17 +61,17 @@ public async Task NotifyEventsTest() //Arrange var segmentName = "segment_test"; var toNotify = new List { { segmentName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); //Act - SdkUpdate = false; + SdkUpdateFlag = false; _cache.AddToSegment(segmentName, new List { "abcd", "zzzzf" }); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); string segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); @@ -78,8 +79,18 @@ public async Task NotifyEventsTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index fd9bac22..689d109b 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; @@ -11,16 +12,17 @@ namespace Splitio_Tests.Unit_Tests.Cache [TestClass] public class SegmentCacheTests { - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; [TestMethod] public void RegisterSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "abcd", "1234" }; var segmentName = "test"; @@ -36,8 +38,8 @@ public void RegisterSegmentTest() public void IsNotInSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -53,8 +55,8 @@ public void IsNotInSegmentTest() public void IsInSegmentWithInexistentSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); //Act var result = segmentCache.IsInSegment("test", "abcd"); @@ -67,8 +69,8 @@ public void IsInSegmentWithInexistentSegmentTest() public void RemoveKeyFromSegmentTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -87,8 +89,8 @@ public void RemoveKeyFromSegmentTest() public void SetAndGetChangeNumberTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var segmentName = "test"; //Act @@ -104,33 +106,33 @@ public void SetAndGetChangeNumberTest() public void NotifyEventsTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); var keys = new List { "1234" }; var segmentName = "test"; var toNotify = new List { { segmentName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act - SdkUpdate = false; + SdkUpdateFlag = false; segmentCache.AddToSegment(segmentName, keys); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); string segment = (string) eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); // Act - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; segmentCache.RemoveFromSegment(segmentName, keys); //Assert - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; Assert.AreEqual(segmentName, segment); @@ -138,8 +140,18 @@ public void NotifyEventsTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 9fb65e65..985b6275 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -18,16 +18,16 @@ public class SplitCacheAsyncTests private readonly IFlagSetsFilter _flagSetsFilter; private readonly IFeatureFlagCache _cache; private readonly EventsManager _eventsManager; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SplitCacheAsyncTests() { _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); - _eventsManager = new EventsManager(new EventsManagerConfig()); - + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); } @@ -193,12 +193,12 @@ public async Task NotifyUpdateEventTest() }); toNotify.Add($"feature-flag-{i}"); } - PublicSdkUpdateHandler += sdkUpdate_callback; - _eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - _eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); - SdkUpdate = false; + SdkUpdateFlag = false; _cache.Update(toAdd, new List(), -1); // Act. @@ -206,7 +206,7 @@ public async Task NotifyUpdateEventTest() // Assert. Assert.AreEqual(5, result.Count); - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 5); @@ -215,11 +215,11 @@ public async Task NotifyUpdateEventTest() Assert.IsTrue(flags.Contains($"feature-flag-{i}")); } - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; _cache.Kill(123, "feature-flag-1", "off"); - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); @@ -228,8 +228,18 @@ public async Task NotifyUpdateEventTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 3d545067..651f66ee 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -15,9 +15,10 @@ namespace Splitio_Tests.Unit_Tests.Cache public class SplitCacheTests { private readonly Mock _flagSetsFilter; - private bool SdkUpdate = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkUpdate; + public event EventHandler SdkReady; public SplitCacheTests() { @@ -28,8 +29,8 @@ public SplitCacheTests() public void AddAndGetSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -44,8 +45,8 @@ public void AddAndGetSplitTest() public void AddDuplicateSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -65,8 +66,8 @@ public void AddDuplicateSplitTest() public void GetInexistentSplitTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; //Act @@ -83,8 +84,8 @@ public void RemoveSplitTest() var splitName = "test1"; var splits = new ConcurrentDictionary(); splits.TryAdd(splitName, new ParsedSplit() { name = splitName }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager.Object); //Act splitCache.Update(new List(), new List { splitName }, -1); @@ -98,8 +99,8 @@ public void RemoveSplitTest() public void SetAndGetChangeNumberTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var changeNumber = 1234; //Act @@ -114,8 +115,8 @@ public void SetAndGetChangeNumberTest() public void GetAllSplitsTest() { //Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "test1"; var splitName2 = "test2"; @@ -134,8 +135,8 @@ public void GetAllSplitsTest() public void AddOrUpdate_WhenUpdateTraffictType_ReturnsTrue() { // Arrange - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); var splitName = "split_1"; var splitName2 = "split_2"; @@ -177,8 +178,8 @@ public void GetNamesByFlagSetsWithoutFilter() Sets = new HashSet { "set1", "set2" } }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -221,8 +222,8 @@ public void GetNamesByFlagSetsWithFilters() defaultTreatment = "on", Sets = new HashSet { "set1", "set2" } }); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager); + Mock> eventsManager = new Mock>(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -244,34 +245,34 @@ public void GetNamesByFlagSetsWithFilters() public void NotifyUpdateEventTest() { // Arrange. - var eventsManager = new EventsManager(new EventsManagerConfig()); + var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); var splitName = "test1"; var toNotify = new List { { splitName } }; - PublicSdkUpdateHandler += sdkUpdate_callback; - eventsManager.Register(SdkEvent.SdkUpdate, sdkUpdate_callback); - eventsManager.Register(SdkEvent.SdkReady, sdkUpdate_callback); + SdkUpdate += sdkUpdate_callback; + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); // Act. - SdkUpdate = false; + SdkUpdateFlag = false; splitCache.Update(new List { new ParsedSplit() { name = splitName } }, new List(), -1); // Assert. - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); Assert.IsTrue(flags.Contains(splitName)); // Act. - SdkUpdate = false; + SdkUpdateFlag = false; eMetadata = null; splitCache.Kill(123, splitName, "off"); // Assert. - Assert.IsTrue(SdkUpdate); + Assert.IsTrue(SdkUpdateFlag); Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; Assert.IsTrue(flags.Count == 1); @@ -280,8 +281,18 @@ public void NotifyUpdateEventTest() private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs index b97cff0e..deb27c04 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs @@ -7,7 +7,7 @@ namespace Splitio_Tests.Unit_Tests.Client { public class LocalhostClientForTesting : LocalhostClient { - public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig())) + public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig(), new EventDelivery())) { } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs index 05f826be..7bdfe24a 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs @@ -21,7 +21,7 @@ public LocalhostClientUnitTests() // This line is to clean the warnings. rootFilePath = string.Empty; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig()); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index 8bd2f7b9..d17713b5 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -9,15 +9,15 @@ namespace Splitio_Tests.Unit_Tests.Client [TestClass] public class InMemoryReadinessGatesCacheUnitTests { - private bool SdkReady = false; + private bool SdkReadyFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkReady; [TestMethod] public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() { //Arrange - var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); //Act var result = gates.IsReady(); @@ -30,23 +30,28 @@ public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() public void TestFireReadyEvent() { //Arrange - EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var gates = new InMemoryReadinessGatesCache(eventsManager); - PublicSdkUpdateHandler += sdkReady_callback; - eventsManager.Register(SdkEvent.SdkReady, PublicSdkUpdateHandler); + SdkReady += sdkReady_callback; + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); //Act gates.SetReady(); // Assert. - Assert.IsTrue(SdkReady); + Assert.IsTrue(SdkReadyFlag); Assert.AreEqual(0, eMetadata.GetData().Count); } private void sdkReady_callback(object sender, EventMetadata metadata) { - SdkReady = true; + SdkReadyFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs index 12277bcb..a44f94eb 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs @@ -23,7 +23,7 @@ public SplitClientForTesting(IFeatureFlagCacheConsumer featureFlagCacheConsumer, ISyncManager syncManager, FallbackTreatmentCalculator fallbackTreatmentCalculator, ITelemetryEvaluationProducer telemetryEvaluationProducer) - : base("SplitClientForTesting", fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig())) + : base("SplitClientForTesting", fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig(), new EventDelivery())) { _eventsLog = eventsLog; _impressionsLog = impressionsLog; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index 80711087..1619f9d1 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Common; -using System; using System.Collections.Generic; namespace Splitio_Tests.Unit_Tests.Common @@ -11,7 +10,6 @@ public class EventDeliveryTests { private bool SdkReady = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkReadyHandler; [TestMethod] public void TestFiringEvents() @@ -19,14 +17,12 @@ public void TestFiringEvents() //Act EventDelivery eventDelivery = new EventDelivery(); - PublicSdkReadyHandler += sdkReady_callback; - Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), PublicSdkReadyHandler); + eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), sdkReady_callback); Assert.IsTrue(SdkReady); VerifyMetadata(eMetadata); @@ -40,7 +36,7 @@ void VerifyMetadata(EventMetadata eMetdata) Assert.IsTrue(flags.Contains("flag1")); } - private void sdkReady_callback(object sender, EventMetadata metadata) + private void sdkReady_callback(EventMetadata metadata) { SdkReady = true; eMetadata = metadata; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 3c1a25d9..5d662d98 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -9,123 +9,123 @@ namespace Splitio_Tests.Unit_Tests.Common [TestClass] public class EventsManagerTests { - private bool SdkReady = false; - private bool SdkReady2 = false; - private bool SdkTimedOut = false; - private bool SdkUpdate = false; + private bool SdkReadyFlag = false; + private bool SdkReadyFlag2 = false; + private bool SdkTimedOutFlag = false; + private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkReadyHandler; - public event EventHandler PublicSdkUpdateHandler; - public event EventHandler PublicSdkTimedOutHandler; + public event EventHandler SdkReady; + public event EventHandler SdkUpdate; + public event EventHandler SdkTimedOut; [TestMethod] public void TestFiringEvents() { //Act EventsManagerConfig config = new EventsManagerConfig(); - EventsManager eventsManager = new EventsManager(config); + EventsManager eventsManager = new EventsManager(config, new EventDelivery()); - PublicSdkReadyHandler += sdkReady_callback; - PublicSdkReadyHandler += sdkReady_callback2; - PublicSdkUpdateHandler += sdkUpdate_callback; - PublicSdkTimedOutHandler += sdkTimedOut_callback; + SdkReady += sdkReady_callback; + SdkReady += sdkReady_callback2; + SdkUpdate += sdkUpdate_callback; + SdkTimedOut += sdkTimedOut_callback; Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } }; - eventsManager.Register(SdkEvent.SdkReady, PublicSdkReadyHandler); - eventsManager.Register(SdkEvent.SdkUpdate, PublicSdkUpdateHandler); + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); // not fired as it is not registered yet + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); // not fired as it is not registered yet - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsTrue(SdkTimedOut); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsTrue(SdkTimedOutFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(500)); - Assert.IsTrue(SdkReady); - Assert.IsTrue(SdkReady2); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); + System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsTrue(SdkReadyFlag); + Assert.IsTrue(SdkReadyFlag2); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkTimedOutHandler); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOut, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); - Assert.IsFalse(SdkTimedOut); // not fired as suppressed by sdkReady + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); + Assert.IsFalse(SdkTimedOutFlag); // not fired as suppressed by sdkReady ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsTrue(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsTrue(SdkUpdateFlag); VerifyMetadata(eMetadata); eventsManager.Unregister(SdkEvent.SdkUpdate); eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); - System.Threading.SpinWait.SpinUntil(() => SdkUpdate, TimeSpan.FromMilliseconds(500)); - Assert.IsFalse(SdkTimedOut); - Assert.IsFalse(SdkReady); - Assert.IsFalse(SdkUpdate); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsFalse(SdkTimedOutFlag); + Assert.IsFalse(SdkReadyFlag); + Assert.IsFalse(SdkUpdateFlag); } void ResetAllVariables() { - SdkReady = false; - SdkReady2 = false; - SdkTimedOut = false; + SdkReadyFlag = false; + SdkReadyFlag2 = false; + SdkTimedOutFlag = false; eMetadata = null; - SdkUpdate = false; + SdkUpdateFlag = false; } void VerifyMetadata(EventMetadata eMetdata) @@ -138,26 +138,42 @@ void VerifyMetadata(EventMetadata eMetdata) private void sdkUpdate_callback(object sender, EventMetadata metadata) { - SdkUpdate = true; + SdkUpdateFlag = true; eMetadata = metadata; } private void sdkReady_callback(object sender, EventMetadata metadata) { - SdkReady = true; + SdkReadyFlag = true; eMetadata = metadata; } private void sdkReady_callback2(object sender, EventMetadata metadata) { - SdkReady2 = true; + SdkReadyFlag2 = true; eMetadata = metadata; } private void sdkTimedOut_callback(object sender, EventMetadata metadata) { - SdkTimedOut = true; + SdkTimedOutFlag = true; eMetadata = metadata; } + + private void TriggerSdkReady(EventMetadata metaData) + { + SdkReady?.Invoke(this, metaData); + } + + private void TriggerSdkUpdate(EventMetadata metaData) + { + SdkUpdate?.Invoke(this, metaData); + } + + private void TriggerSdkTimeout(EventMetadata metaData) + { + SdkTimedOut?.Invoke(this, metaData); + } + } } diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index 42df730c..aad37a8d 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -29,7 +29,7 @@ public void Start_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -53,7 +53,7 @@ public void Start_ShouldNotSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -72,7 +72,7 @@ public async Task Stop_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -96,7 +96,7 @@ public async Task Stop_ShouldSendImpressionsCount() public async Task ShouldSend2BulksOfImpressions() { var config = new ComponentConfig(6, 3); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs index 78a1efc7..6292b5d5 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs @@ -6,6 +6,7 @@ using Splitio.Services.Impressions.Interfaces; using Splitio.Services.Tasks; using Splitio.Telemetry.Domain; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; @@ -51,8 +52,7 @@ public async Task PeriodicTask_ShouldSendBulk() // Assert. Assert.IsTrue(_uniqueKeysTracker.Track("key-test", "feature-name-test")); - Thread.Sleep(2000); - + System.Threading.SpinWait.SpinUntil(() => _cache.Count == 0, TimeSpan.FromMilliseconds(2000)); _senderAdapter.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Once); Assert.IsTrue(_uniqueKeysTracker.Track("key-test", "feature-name-test")); @@ -104,7 +104,7 @@ public void Track_WithFullSize_ShouldSendTwoBulk() Thread.Sleep(1000); Assert.IsTrue(_uniqueKeysTracker.Track("key-test-2", "feature-name-test-6")); - Thread.Sleep(3000); + System.Threading.SpinWait.SpinUntil(() => _cache.Count==0, TimeSpan.FromMilliseconds(3000)); _senderAdapter.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Exactly(2)); _cache.Clear(); @@ -143,8 +143,8 @@ public void Track_WithFullSize_ShouldSplitBulks() Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-4", "feature-name-test-2")); Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-5", "feature-name-test-2")); Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-6", "feature-name-test-2")); - Thread.Sleep(1000); + System.Threading.SpinWait.SpinUntil(() => _cache2.Count == 0, TimeSpan.FromMilliseconds(3000)); _senderAdapter2.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Exactly(4)); _cache2.Clear(); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs index e870361b..f3a0ff0e 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs @@ -1,4 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; @@ -23,8 +24,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -47,8 +48,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -65,8 +66,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -83,8 +84,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -106,8 +107,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -130,8 +131,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -148,8 +149,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -166,8 +167,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs index 11239973..f7c1245c 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs @@ -1,10 +1,11 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Splitio.Services.Parsing; +using Moq; using Splitio.Domain; -using System.Collections.Generic; -using System.Collections.Concurrent; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; +using Splitio.Services.Parsing; +using System.Collections.Concurrent; +using System.Collections.Generic; namespace Splitio_Tests.Unit_Tests { @@ -22,8 +23,8 @@ public void MatchShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -46,8 +47,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -64,8 +65,8 @@ public void MatchShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -82,8 +83,8 @@ public void MatchShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -105,8 +106,8 @@ public void MatchShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -129,8 +130,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -147,8 +148,8 @@ public void MatchShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -165,8 +166,8 @@ public void MatchShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - var eventsManager = new EventsManager(new EventsManagerConfig()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + Mock> eventsManager = new Mock>(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 97a68959..766ddd16 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -11,6 +11,7 @@ using Splitio.Services.Shared.Interfaces; using Splitio.Services.SplitFetcher.Interfaces; using Splitio.Services.Tasks; +using Splitio.Telemetry.Domain; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; @@ -27,13 +28,13 @@ public class SelfRefreshingSegmentFetcherUnitTests public void InitializeSegmentNotExistent() { // Arrange - var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + Mock> eventsManager = new Mock>(); + var gates = new InMemoryReadinessGatesCache(eventsManager.Object); gates.SetReady(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(5, segmentsQueue); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs index 06f32feb..83074558 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs @@ -23,8 +23,8 @@ public async Task FetchSegmentNullChangesFetcherResponseShouldNotUpdateCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient @@ -46,8 +46,8 @@ public async Task FetchSegmentShouldUpdateSegmentsCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var eventsManager = new EventsManager(new EventsManagerConfig()); - var cache = new InMemorySegmentCache(segments, eventsManager); + Mock> eventsManager = new Mock>(); + var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index 120072f3..6f63501d 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -12,9 +12,9 @@ namespace Splitio_Tests.Unit_Tests.Shared [TestClass] public class SelfRefreshingBlockUntilReadyServiceTests { - private bool SdkTimedOut = false; + private bool SdkTimedOutFlag = false; private EventMetadata eMetadata = null; - public event EventHandler PublicSdkUpdateHandler; + public event EventHandler SdkTimedOut; [TestMethod] public void TestFireTimedOutEvent() @@ -22,10 +22,10 @@ public void TestFireTimedOutEvent() //Arrange Mock statusManager = new Mock(); Mock telemetryProducer = new Mock(); - EventsManager eventsManager = new EventsManager(new EventsManagerConfig()); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, eventsManager); - PublicSdkUpdateHandler += SdkTimedOut_callback; - eventsManager.Register(SdkEvent.SdkReadyTimeout, PublicSdkUpdateHandler); + SdkTimedOut += sdkTimeout_callback; + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimedOut); statusManager .Setup(mock => mock.WaitUntilReady(1)) .Returns(false); @@ -38,14 +38,19 @@ public void TestFireTimedOutEvent() catch { } // Assert. - Assert.IsTrue(SdkTimedOut); + Assert.IsTrue(SdkTimedOutFlag); Assert.AreEqual(0, eMetadata.GetData().Count); } - private void SdkTimedOut_callback(object sender, EventMetadata metadata) + private void sdkTimeout_callback(object sender, EventMetadata metadata) { - SdkTimedOut = true; + SdkTimedOutFlag = true; eMetadata = metadata; } + + private void TriggerSdkTimedOut(EventMetadata metaData) + { + SdkTimedOut?.Invoke(this, metaData); + } } } diff --git a/tests/Splitio.Integration-tests/EventSourceClientTests.cs b/tests/Splitio.Integration-tests/EventSourceClientTests.cs index 0eb26bdd..b7850c78 100644 --- a/tests/Splitio.Integration-tests/EventSourceClientTests.cs +++ b/tests/Splitio.Integration-tests/EventSourceClientTests.cs @@ -370,7 +370,7 @@ private static (IEventSourceClient, BlockingCollection, var sseHttpClient = new SplitioHttpClient("api-key", config, new Dictionary()); var telemetryRuntimeProducer = new InMemoryTelemetryStorage(); var notificationManagerKeeper = new NotificationManagerKeeper(telemetryRuntimeProducer, streamingStatusQueue); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); var tasksManager = new TasksManager(statusManager); var task = tasksManager.NewOnTimeTask(Enums.Task.SSEConnect); diff --git a/tests/Splitio.Integration-tests/PollingClientTests.cs b/tests/Splitio.Integration-tests/PollingClientTests.cs index 37c97ee7..8b01959c 100644 --- a/tests/Splitio.Integration-tests/PollingClientTests.cs +++ b/tests/Splitio.Integration-tests/PollingClientTests.cs @@ -18,6 +18,7 @@ namespace Splitio.Integration_tests public class PollingClientTests : BaseIntegrationTests { private static readonly HttpClientMock httpClientMock = new HttpClientMock("PollingClientTests"); + private bool SdkTimeout = false; public PollingClientTests() : base("Polling") { } @@ -161,7 +162,8 @@ public void GetTreatment_WithtBUR_ReturnsTimeOutException() var apikey = "apikey5"; var splitFactory = new SplitFactory(apikey, configurations); - var client = splitFactory.Client(); + var client = (SplitClient)splitFactory.Client(); + client.SdkTimedOut += sdkTimeout_callback; // Act. var exceptionMessage = ""; @@ -178,6 +180,7 @@ public void GetTreatment_WithtBUR_ReturnsTimeOutException() } // Assert. + Assert.IsTrue(SdkTimeout); Assert.IsFalse(isSdkReady); Assert.AreEqual("SDK was not ready in 0 milliseconds", exceptionMessage); @@ -400,7 +403,7 @@ public void Telemetry_ValidatesConfigInitAndStats() try { - client.BlockUntilReady(0); + client.BlockUntilReady(1); } catch { @@ -412,7 +415,8 @@ public void Telemetry_ValidatesConfigInitAndStats() // Assert. Assert.AreEqual("on", result); - + + System.Threading.SpinWait.SpinUntil(() => (GetMetricsConfigSentBackend(httpClientMock) != null) , TimeSpan.FromMilliseconds(1000)); var sentConfig = GetMetricsConfigSentBackend(httpClientMock); Assert.IsNotNull(sentConfig); Assert.AreEqual(configurations.StreamingEnabled, sentConfig.StreamingEnabled); @@ -724,6 +728,11 @@ private static List GetImpressionsCountsSentBackend(HttpClientM return impressions; } + + private void sdkTimeout_callback(object sender, EventMetadata metadata) + { + SdkTimeout = true; + } #endregion } } diff --git a/tests/Splitio.Integration-tests/StreamingClientTests.cs b/tests/Splitio.Integration-tests/StreamingClientTests.cs index 7623dadd..6a22ec53 100644 --- a/tests/Splitio.Integration-tests/StreamingClientTests.cs +++ b/tests/Splitio.Integration-tests/StreamingClientTests.cs @@ -22,6 +22,10 @@ namespace Splitio.Integration_tests public class StreamingClientTests { public static string EventSourcePath => "/eventsource"; + private bool SdkReady = false; + private bool SdkReady2 = false; + private bool SdkReady3 = false; + private bool SdkUpdate = false; [TestMethod] public void GetTreatment_SplitUpdate_ShouldFetch() @@ -56,18 +60,28 @@ public void GetTreatment_SplitUpdate_ShouldFetch() SegmentsRefreshRate = 3000, AuthServiceURL = $"{url}/api/auth", StreamingServiceURL = $"{url}{EventSourcePath}", - StreamingEnabled = true + StreamingEnabled = true, + Logger = SplitLogger.Console(Level.Debug) }; var apikey = "apikey1"; var splitFactory = new SplitFactory(apikey, config); - var client = splitFactory.Client(); + var client = (SplitClient)splitFactory.Client(); + client.SdkReady += sdkReady_callback; + client.SdkReady += sdkReady_callback2; + client.SdkUpdate += sdkUpdate_callback; client.BlockUntilReady(10000); var result = EvaluateWithDelay("admin", "push_test", "after_fetch", client); + client.SdkReady += sdkReady_callback3; + Assert.AreEqual("after_fetch", result); + Assert.IsTrue(SdkReady); + Assert.IsTrue(SdkReady2); + Assert.IsTrue(SdkReady3); + Assert.IsTrue(SdkUpdate); client.Destroy(); } @@ -112,13 +126,11 @@ public void GetTreatment_SplitUpdate_ShouldNotFetch() var splitFactory = new SplitFactory(apikey, config); var client = splitFactory.Client(); - client.BlockUntilReady(10000); var result = EvaluateWithDelay("admin", "push_test", "on", client); Assert.AreEqual("on", result); - client.Destroy(); } } @@ -765,5 +777,25 @@ public static string EvaluateWithDelay(string key, string splitName, string expe return result; } + + private void sdkReady_callback(object sender, EventMetadata metadata) + { + SdkReady = true; + } + + private void sdkReady_callback2(object sender, EventMetadata metadata) + { + SdkReady2 = true; + } + + private void sdkReady_callback3(object sender, EventMetadata metadata) + { + SdkReady3 = true; + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; + } } } diff --git a/tests/Splitio.TestSupport/SplitClientForTest.cs b/tests/Splitio.TestSupport/SplitClientForTest.cs index f79f6674..363380c2 100644 --- a/tests/Splitio.TestSupport/SplitClientForTest.cs +++ b/tests/Splitio.TestSupport/SplitClientForTest.cs @@ -11,7 +11,7 @@ public class SplitClientForTest : SplitClient private readonly Dictionary _tests; public SplitClientForTest() : base("SplitClientForTest", new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()), - new EventsManager(new EventsManagerConfig())) + new EventsManager(new EventsManagerConfig(), new EventDelivery())) { _tests = new Dictionary(); } From 4516fab4b73661ea83fbc96b5242d074d8583dae Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 26 Dec 2025 13:13:27 -0800 Subject: [PATCH 58/87] moved creating eventsManager and FallbackTreatment instances to client --- .../Services/Client/Classes/RedisClient.cs | 6 +- .../Services/Client/Classes/JSONFileClient.cs | 13 ++- .../Client/Classes/LocalhostClient.cs | 8 +- .../Client/Classes/SelfRefreshingClient.cs | 6 +- .../Services/Client/Classes/SplitClient.cs | 9 +- .../Services/Client/Classes/SplitFactory.cs | 11 +-- .../BaseLocalhostClientTests.cs | 37 +++---- .../Integration Tests/InMemoryClientTests.cs | 6 +- .../Integration Tests/JSONFileClientTests.cs | 98 +++++++++---------- .../Integration Tests/RedisClientTests.cs | 59 +++++------ .../Client/LocalhostClientForTesting.cs | 7 +- .../Client/LocalhostClientUnitTests.cs | 9 +- .../Client/SplitClientAsyncTests.cs | 10 +- .../Client/SplitClientForTesting.cs | 10 +- .../Unit Tests/Client/SplitClientUnitTests.cs | 9 +- .../Impressions/ImpressionsCounterTests.cs | 6 +- .../SelfRefreshingSegmentFetcherUnitTests.cs | 2 +- .../Splitio.TestSupport/Samples/SampleTest.cs | 6 +- .../Splitio.TestSupport/SplitClientForTest.cs | 3 +- 19 files changed, 137 insertions(+), 178 deletions(-) diff --git a/Splitio.Redis/Services/Client/Classes/RedisClient.cs b/Splitio.Redis/Services/Client/Classes/RedisClient.cs index 345a546d..f8027320 100644 --- a/Splitio.Redis/Services/Client/Classes/RedisClient.cs +++ b/Splitio.Redis/Services/Client/Classes/RedisClient.cs @@ -9,7 +9,6 @@ using Splitio.Redis.Telemetry.Storages; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Client.Classes; -using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Evaluator; using Splitio.Services.Impressions.Classes; @@ -29,13 +28,10 @@ public class RedisClient : SplitClient private IImpressionsCache _impressionsCache; private ConnectionPoolManager _connectionPoolManager; private IFeatureFlagCacheConsumer _featureFlagCacheConsumer; - private readonly new FallbackTreatmentCalculator _fallbackTreatmentCalculator; - public RedisClient(ConfigurationOptions config, string apiKey, FallbackTreatmentCalculator fallbackTreatmentCalculator, - EventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) + public RedisClient(ConfigurationOptions config, string apiKey) : base(apiKey, config) { _config = new RedisConfig(); - _fallbackTreatmentCalculator = fallbackTreatmentCalculator; ReadConfig(config); diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index cae07f34..5c2faeba 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -24,8 +24,7 @@ public class JSONFileClient : SplitClient public JSONFileClient(string splitsFilePath, string segmentsFilePath, - FallbackTreatmentCalculator fallbackTreatmentCalculator, - EventsManager eventsManager, + ConfigurationOptions config, ISegmentCache segmentCacheInstance = null, IFeatureFlagCache featureFlagCacheInstance = null, IImpressionsLog impressionsLog = null, @@ -34,10 +33,10 @@ public JSONFileClient(string splitsFilePath, ITrafficTypeValidator trafficTypeValidator = null, IImpressionsManager impressionsManager = null, IRuleBasedSegmentCache ruleBasedSegmentCache = null - ) : base("localhost", fallbackTreatmentCalculator, eventsManager) + ) : base("localhost", config) { - _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); - var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); + _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), _eventsManager); + var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), _eventsManager); var segmentFetcher = new JSONFileSegmentFetcher(segmentsFilePath, _segmentCache); var splitChangeFetcher = new JSONFileSplitChangeFetcher(splitsFilePath); @@ -55,13 +54,13 @@ public JSONFileClient(string splitsFilePath, } BuildFlagSetsFilter(new HashSet()); - _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, eventsManager); + _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _eventsManager); _impressionsLog = impressionsLog; _eventsLog = eventsLog; _trafficTypeValidator = trafficTypeValidator; _blockUntilReadyService = new NoopBlockUntilReadyService(); _manager = new SplitManager(_featureFlagCache, _blockUntilReadyService); - _evaluator = new Evaluator.Evaluator(_featureFlagCache, new Splitter(), null, fallbackTreatmentCalculator); + _evaluator = new Evaluator.Evaluator(_featureFlagCache, new Splitter(), null, _fallbackTreatmentCalculator); _uniqueKeysTracker = new NoopUniqueKeysTracker(); _impressionsCounter = new NoopImpressionsCounter(); _impressionsObserver = new NoopImpressionsObserver(); diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index b22c5f07..96495a1a 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -1,7 +1,6 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Impressions.Classes; using Splitio.Services.InputValidation.Classes; @@ -28,8 +27,7 @@ public class LocalhostClient : SplitClient private readonly object _lock = new object(); - public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatmentCalculator fallbackTreatmentCalculator, - EventsManager eventsManager) : base("localhost", fallbackTreatmentCalculator, eventsManager) + public LocalhostClient(ConfigurationOptions configurationOptions) : base("localhost", configurationOptions) { var configs = (LocalhostClientConfigurations)_configService.ReadConfig(configurationOptions, ConfigTypes.Localhost, _statusManager); @@ -49,7 +47,7 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm BuildFlagSetsFilter(new HashSet()); var splits = _localhostFileService.ParseSplitFile(_fullPath); - _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, eventsManager); + _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); if (configs.FileSync != null) @@ -64,7 +62,7 @@ public LocalhostClient(ConfigurationOptions configurationOptions, FallbackTreatm _blockUntilReadyService = new NoopBlockUntilReadyService(); _manager = new SplitManager(_featureFlagCache, _blockUntilReadyService); _trafficTypeValidator = new TrafficTypeValidator(_featureFlagCache, _blockUntilReadyService); - _evaluator = new Evaluator.Evaluator(_featureFlagCache, new Splitter(), null, fallbackTreatmentCalculator); + _evaluator = new Evaluator.Evaluator(_featureFlagCache, new Splitter(), null, _fallbackTreatmentCalculator); _uniqueKeysTracker = new NoopUniqueKeysTracker(); _impressionsCounter = new NoopImpressionsCounter(); _impressionsObserver = new NoopImpressionsObserver(); diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 7d513bc5..14fae995 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -51,14 +51,10 @@ public class SelfRefreshingClient : SplitClient private IUpdater _featureFlagUpdater; private IRuleBasedSegmentCache _ruleBasedSegmentCache; private IUpdater _ruleBasedSegmentUpdater; - private readonly new FallbackTreatmentCalculator _fallbackTreatmentCalculator; - public SelfRefreshingClient(string apiKey, ConfigurationOptions config, - FallbackTreatmentCalculator fallbackTreatmentCalculator, - IEventsManager eventsManager) : base(apiKey, fallbackTreatmentCalculator, eventsManager) + public SelfRefreshingClient(string apiKey, ConfigurationOptions config) : base(apiKey, config) { _config = (SelfRefreshingConfig)_configService.ReadConfig(config, ConfigTypes.InMemory); - _fallbackTreatmentCalculator = fallbackTreatmentCalculator; BuildFlagSetsFilter(_config.FlagSetsFilter); BuildSplitCache(); diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 801e416b..82c99b1e 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -69,15 +69,16 @@ public abstract class SplitClient : ISplitClient public event EventHandler SdkUpdate; public event EventHandler SdkTimedOut; - protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatmentCalculator, IEventsManager eventsManager) + protected SplitClient(string apikey, ConfigurationOptions options) { ApiKey = apikey; - _eventsManager = eventsManager; + _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(options.FallbackTreatments); + _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReadyEvent); _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdateEvent); _eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeoutEvent); - _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _wrapperAdapter = WrapperAdapter.Instance(); _keyValidator = new KeyValidator(); _splitNameValidator = new SplitNameValidator(); @@ -86,7 +87,7 @@ protected SplitClient(string apikey, FallbackTreatmentCalculator fallbackTreatme _factoryInstantiationsService = FactoryInstantiationsService.Instance(); _flagSetsValidator = new FlagSetsValidator(); _configService = new ConfigService(_wrapperAdapter, _flagSetsValidator, new SdkMetadataValidator()); - _statusManager = new InMemoryReadinessGatesCache(eventsManager); + _statusManager = new InMemoryReadinessGatesCache(_eventsManager); _tasksManager = new TasksManager(_statusManager); } diff --git a/src/Splitio/Services/Client/Classes/SplitFactory.cs b/src/Splitio/Services/Client/Classes/SplitFactory.cs index 27742c36..1cb95e98 100644 --- a/src/Splitio/Services/Client/Classes/SplitFactory.cs +++ b/src/Splitio/Services/Client/Classes/SplitFactory.cs @@ -1,7 +1,5 @@ using Splitio.Domain; using Splitio.Services.Client.Interfaces; -using Splitio.Services.Common; -using Splitio.Services.Impressions.Classes; using Splitio.Services.InputValidation.Classes; using Splitio.Services.InputValidation.Interfaces; using Splitio.Services.Shared.Classes; @@ -59,9 +57,6 @@ public ISplitManager Manager() private void BuildSplitClient() { - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(_options.FallbackTreatments); - EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - switch (_options.Mode) { case Mode.Standalone: @@ -69,11 +64,11 @@ private void BuildSplitClient() if (_apiKey == "localhost") { - _client = new LocalhostClient(_options, fallbackTreatmentCalculator, eventsManager); + _client = new LocalhostClient(_options); } else { - _client = new SelfRefreshingClient(_apiKey, _options, fallbackTreatmentCalculator, eventsManager); + _client = new SelfRefreshingClient(_apiKey, _options); } break; case Mode.Consumer: @@ -84,7 +79,7 @@ private void BuildSplitClient() var redisAssembly = Assembly.Load(new AssemblyName("Splitio.Redis")); var redisType = redisAssembly.GetType("Splitio.Redis.Services.Client.Classes.RedisClient"); - _client = (ISplitClient)Activator.CreateInstance(redisType, new object[] { _options, _apiKey, fallbackTreatmentCalculator, eventsManager }); + _client = (ISplitClient)Activator.CreateInstance(redisType, new object[] { _options, _apiKey }); } catch (ArgumentException ex) { diff --git a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs index 9bb56c7f..26313394 100644 --- a/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/BaseLocalhostClientTests.cs @@ -1,10 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; -using Splitio.Redis.Services.Client.Classes; using Splitio.Services.Client.Classes; -using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; -using Splitio.Telemetry.Domain; using System; using System.Collections.Generic; using System.IO; @@ -24,16 +21,12 @@ public abstract class BaseLocalhostClientTests { private readonly string rootFilePath; private readonly string _mode; - private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; - private readonly EventsManager _eventsManager; public BaseLocalhostClientTests(string mode) { // This line is to clean the warnings. rootFilePath = string.Empty; _mode = mode; - _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -45,7 +38,7 @@ public async Task GetTreatmentAsync() { // Arrange. var config = GetConfiguration($"{rootFilePath}test.splits"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -84,7 +77,7 @@ public void GetTreatmentSuccessfully() { //Arrange var config = GetConfiguration($"{rootFilePath}test.splits"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -108,7 +101,7 @@ public void GetTreatmentSuccessfullyWhenUpdatingSplitsFile() // Arrange var filePath = $"{rootFilePath}test2-{_mode}.splits"; var config = GetConfiguration(filePath); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -151,7 +144,7 @@ public void GetTreatmentSuccessfullyWhenUpdatingSplitsFileSameFile() Thread.Sleep(1000); var config = GetConfiguration(filePath); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -174,7 +167,7 @@ public void ClientDestroySuccessfully() { //Arrange var config = GetConfiguration($"{rootFilePath}test.splits"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -196,7 +189,7 @@ public void GetTreatment_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -228,7 +221,7 @@ public void GetTreatmentWithConfig_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -267,7 +260,7 @@ public void GetTreatment_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -299,7 +292,7 @@ public void GetTreatmentWithConfig_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -338,7 +331,7 @@ public void GetTreatments_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -375,7 +368,7 @@ public void GetTreatmentsWithConfig_WhenIsYamlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -426,7 +419,7 @@ public void GetTreatments_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -463,7 +456,7 @@ public void GetTreatmentsWithConfig_WhenIsYmlFile_Successfully() { //Arrange var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, _fallbackTreatmentCalculator, _eventsManager); + var client = new LocalhostClient(config); client.BlockUntilReady(1000); @@ -514,10 +507,10 @@ public void FallbackTreatments_WhenFeatureDoesNotExist() { var features = new List { "testing_split_on", "feature", "feature2" }; FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); var config = GetConfiguration($"{rootFilePath}split.yml"); - var client = new LocalhostClient(config, fallbackTreatmentCalculator, _eventsManager); + config.FallbackTreatments = fallbackTreatmentsConfiguration; + var client = new LocalhostClient(config); client.BlockUntilReady(1000); diff --git a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs index e16d7f0f..cf591e65 100644 --- a/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/InMemoryClientTests.cs @@ -12,15 +12,11 @@ namespace Splitio_Tests.Integration_Tests public class InMemoryClientTests { private readonly string rootFilePath; - private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; - private readonly EventsManager _eventsManager; public InMemoryClientTests() { // This line is to clean the warnings. rootFilePath = string.Empty; - _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -39,7 +35,7 @@ public void OverridingJsonConvertSettingSnakeCaseNamingStrategy() NamingStrategy = new SnakeCaseNamingStrategy() } }; - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); //Act diff --git a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs index c4868dea..5ad0ea23 100644 --- a/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/JSONFileClientTests.cs @@ -19,15 +19,11 @@ namespace Splitio_Tests.Integration_Tests public class JSONFileClientTests { private readonly string rootFilePath; - private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; - private readonly EventsManager _eventsManager; public JSONFileClientTests() { // This line is to clean the warnings. rootFilePath = string.Empty; - _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; @@ -40,7 +36,7 @@ public JSONFileClientTests() public void ExecuteGetTreatmentOnFailedParsingSplitShouldReturnControl() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); //Act var result = client.GetTreatment("test", "fail", null); @@ -55,7 +51,7 @@ public void ExecuteGetTreatmentOnFailedParsingSplitShouldReturnControl() public void ExecuteGetTreatmentOnFailedParsingSplitShouldNotAffectOtherSplits() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -72,7 +68,7 @@ public void ExecuteGetTreatmentOnFailedParsingSplitShouldNotAffectOtherSplits() public void ExecuteGetTreatmentOnDeletedSplitShouldReturnControl() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -100,7 +96,7 @@ public void ExecuteGetTreatmentOnExceptionShouldReturnControl() .Setup(x => x.GetSplit(It.IsAny())) .Throws(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, null, splitCacheMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions(), featureFlagCacheInstance: splitCacheMock.Object, impressionsLog: impressionsLogMock.Object); //Act var result = client.GetTreatment("test", "asd", null); @@ -116,7 +112,7 @@ public void ExecuteGetTreatmentOnExceptionShouldReturnControl() public void ExecuteGetTreatmentOnRemovedUserFromSegmentShouldReturnOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", $"{rootFilePath}segment_payed.json", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", $"{rootFilePath}segment_payed.json", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -138,7 +134,7 @@ public void ExecuteGetTreatmentOnRemovedUserFromSegmentShouldReturnOff() public void ExecuteGetTreatmentOnSplitWithOnOffOnPartition() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -162,7 +158,7 @@ public void ExecuteGetTreatmentOnSplitWithOnOffOnPartition() public void ExecuteGetTreatmentOnSplitWithTrafficAllocation() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -186,7 +182,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocation() public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIsDifferentThan100() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -210,7 +206,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIsDiffe public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1ReturnsRolloutTreatment() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -226,7 +222,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1Retu public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1ReturnsDefaultTreatment() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_7.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -242,7 +238,7 @@ public void ExecuteGetTreatmentOnSplitWithTrafficAllocationWhenAllocationIs1Retu public void ExecuteGetTreatmentOnSplitWithSegmentNotInitialized() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -262,7 +258,7 @@ public void ExecuteGetTreatmentAndLogLabelKilled() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions(), impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -286,7 +282,7 @@ public void ExecuteGetTreatmentAndLogLabelNoConditionMatched() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions(), impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -310,7 +306,7 @@ public void ExecuteGetTreatmentAndLogLabelSplitNotFound() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); //Act client.RemoveSplitFromCache("asd"); @@ -339,7 +335,7 @@ public void ExecuteGetTreatmentAndLogLabelException() .Setup(x => x.GetSplit(It.IsAny())) .Throws(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, featureFlagCacheInstance: splitCacheMock.Object, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions { ImpressionsMode = ImpressionsMode.Debug }, impressionsLog: impressionsLogMock.Object, featureFlagCacheInstance: splitCacheMock.Object); client.BlockUntilReady(1000); @@ -363,7 +359,7 @@ public void ExecuteGetTreatmentAndLogLabelTrafficAllocationFailed() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", new ConfigurationOptions(), impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -386,7 +382,7 @@ public void ExecuteGetTreatmentAndLogLabelForTreatment() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions(), impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -409,7 +405,7 @@ public void ExecuteGetTreatmentAndLogLabelForTreatment() public void ExecuteGetTreatmentWhenUnknownMatcherIsIncluded() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); //Act var result = client.GetTreatment("xs", "Unknown_Matcher", null); @@ -424,7 +420,7 @@ public void ExecuteGetTreatmentAndNotLogLabelForTreatmentIfLabelsNotEnabled() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object, isLabelsEnabled: false); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions(), impressionsLog: impressionsLogMock.Object, isLabelsEnabled: false); client.BlockUntilReady(1000); @@ -447,7 +443,7 @@ public void ExecuteGetTreatmentAndLogLabelAndBucketingKeyForTreatment() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions { ImpressionsMode = ImpressionsMode.Debug }, impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -471,7 +467,7 @@ public void ExecuteGetTreatmentAndLogLabelAndBucketingKeyForTreatment() public void ExecuteGetTreatmentWithBooleanAttribute() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_4.json", "", new ConfigurationOptions()); var attributes = new Dictionary { @@ -493,7 +489,7 @@ public void ExecuteGetTreatmentWithBooleanAttribute() public void ExecuteGetTreatmentWithSetMatcherReturnsOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", new ConfigurationOptions()); var attributes = new Dictionary { @@ -515,7 +511,7 @@ public void ExecuteGetTreatmentWithSetMatcherReturnsOff() public void ExecuteGetTreatmentWithSetMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", new ConfigurationOptions()); var attributes = new Dictionary { @@ -537,7 +533,7 @@ public void ExecuteGetTreatmentWithSetMatcherReturnsOn() public void ExecuteGetTreatmentWithStringMatcherReturnsOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", new ConfigurationOptions()); var attributes = new Dictionary { @@ -559,7 +555,7 @@ public void ExecuteGetTreatmentWithStringMatcherReturnsOff() public void ExecuteGetTreatmentWithStringMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", new ConfigurationOptions()); var attributes = new Dictionary { @@ -581,7 +577,7 @@ public void ExecuteGetTreatmentWithStringMatcherReturnsOn() public void ExecuteGetTreatmentWithDependencyMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -598,7 +594,7 @@ public void ExecuteGetTreatmentWithDependencyMatcherReturnsOn() public void ExecuteGetTreatmentWithDependencyMatcherReturnsOff() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -616,7 +612,7 @@ public void ExecuteGetTreatmentWithDependencyMatcherImpressionOnChild() { //Arrange var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager,impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", new ConfigurationOptions(),impressionsLog: impressionsLogMock.Object); client.BlockUntilReady(1000); @@ -634,7 +630,7 @@ public void GetTreatment_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); var splitName = "not_exist"; client.BlockUntilReady(1000); @@ -652,7 +648,7 @@ public void GetTreatment_WhenNameDoesntExist_DontLogImpression() public void GetTreatment_WithoutBlockUntiltReady_ReturnsOff() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); // Act. var result = client.GetTreatment("key", "anding"); @@ -668,7 +664,7 @@ public void GetTreatment_WithoutBlockUntiltReady_ReturnsOff() public void ExecuteGetTreatments() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); List features = new List { "fail", @@ -699,7 +695,7 @@ public void ExecuteGetTreatments() public void ExecuteGetTreatmentsWithBucketing() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); List features = new List { "fail", @@ -731,7 +727,7 @@ public void ExecuteGetTreatmentsWithBucketing() public void ExecuteGetTreatmentsWithDependencyMatcherReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -754,7 +750,7 @@ public void ExecuteGetTreatmentsWithDependencyMatcherReturnsOn() public void ExecuteGetTreatmentsWithDependencyMatcherWithAttributesReturnsOn() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_6.json", "", new ConfigurationOptions()); client.BlockUntilReady(1000); @@ -782,7 +778,7 @@ public void GetTreatments_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); var splitNames = new List { "not_exist", "not_exist_1" }; client.BlockUntilReady(1000); @@ -804,7 +800,7 @@ public void GetTreatments_WhenNameDoesntExist_DontLogImpression() public void GetTreatments_WithoutBlockUntiltReady_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); // Act. var result = client.GetTreatments("key", new List()); @@ -818,7 +814,7 @@ public void GetTreatments_WithoutBlockUntiltReady_ReturnsEmptyList() public void GetTreatments_WithoutBlockUntiltReady_ReturnsTreatments() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); // Act. var result = client.GetTreatments("key", new List { "anding", "in_ten_keys" }); @@ -836,7 +832,7 @@ public void GetTreatments_WithoutBlockUntiltReady_ReturnsTreatments() public void GetTreatments_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); client.BlockUntilReady(100); // Act. @@ -853,7 +849,7 @@ public void GetTreatments_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsEmptyList() public void DestroySucessfully() { //Arrange - var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_5.json", "", new ConfigurationOptions()); var attributes = new Dictionary { @@ -889,7 +885,7 @@ public void Track_WhenClientIsNotReady_ReturnsTrue() // Arrange. var trafficTypeValidator = new Mock(); var eventLog = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, trafficTypeValidator: trafficTypeValidator.Object, eventsLog: eventLog.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions(), trafficTypeValidator: trafficTypeValidator.Object, eventsLog: eventLog.Object); trafficTypeValidator .Setup(mock => mock.IsValid(It.IsAny(), It.IsAny())) @@ -910,7 +906,7 @@ public void GetTreatmentWithConfig_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); var splitName = "not_exist"; client.BlockUntilReady(1000); @@ -929,7 +925,7 @@ public void GetTreatmentWithConfig_WhenNameDoesntExist_DontLogImpression() public void GetTreatmentWithConfig_WithoutBlockUntiltReady_ReturnsOff() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); // Act. var result = client.GetTreatmentWithConfig("key", "anding"); @@ -947,7 +943,7 @@ public void GetTreatmentsWithConfig_WhenNameDoesntExist_DontLogImpression() { // Arrange. var impressionsLogMock = new Mock(); - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager, impressionsLog: impressionsLogMock.Object); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); var splitNames = new List { "not_exist", "not_exist_1" }; client.BlockUntilReady(1000); @@ -970,7 +966,7 @@ public void GetTreatmentsWithConfig_WhenNameDoesntExist_DontLogImpression() public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); // Act. var result = client.GetTreatmentsWithConfig("anding", new List()); @@ -984,7 +980,7 @@ public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsEmptyList() public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsTreatments() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); // Act. var result = client.GetTreatmentsWithConfig("key", new List { "anding", "whitelisting_elements" }); @@ -1004,7 +1000,7 @@ public void GetTreatmentsWithConfig_WithoutBlockUntiltReady_ReturnsTreatments() public void GetTreatmentsWithConfig_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsEmptyList() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); client.BlockUntilReady(100); // Act. @@ -1021,7 +1017,7 @@ public void GetTreatmentsWithConfig_WhenClientIsReadyAndFeaturesIsEmpty_ReturnsE public void Split_Manager_WhenNameDoesntExist_ReturnsNull() { // Arrange. - var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", _fallbackTreatmentCalculator, _eventsManager); + var client = new JSONFileClient($"{rootFilePath}splits_staging_3.json", "", new ConfigurationOptions()); var manager = client.GetSplitManager(); var splitName = "not_exist"; diff --git a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs index f600179a..5b7ea4c7 100644 --- a/tests/Splitio-tests/Integration Tests/RedisClientTests.cs +++ b/tests/Splitio-tests/Integration Tests/RedisClientTests.cs @@ -67,7 +67,7 @@ public void Initialization() public void GetTreatment_WhenFeatureExists_ReturnsOn() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); @@ -78,7 +78,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOn() Assert.IsNotNull(result); Assert.AreEqual("on", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); @@ -94,7 +94,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOn() public void GetTreatment_WhenFeatureExists_ReturnsOff() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); @@ -105,7 +105,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOff() Assert.IsNotNull(result); Assert.AreEqual("off", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatment("test", "always_off", null); @@ -119,7 +119,7 @@ public void GetTreatment_WhenFeatureExists_ReturnsOff() public void GetTreatment_WhenFeatureDoenstExist_ReturnsControl() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); //Act @@ -129,7 +129,7 @@ public void GetTreatment_WhenFeatureDoenstExist_ReturnsControl() Assert.IsNotNull(result); Assert.AreEqual("control", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatment("test", "always_control", null); @@ -148,7 +148,7 @@ public void GetTreatments_WhenFeaturesExists_ReturnsOnOff() var features = new List { alwaysOn, alwaysOff }; - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); @@ -162,7 +162,7 @@ public void GetTreatments_WhenFeaturesExists_ReturnsOnOff() var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), - API_KEY, _fallbackTreatmentCalculator, _eventsManager); + API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatments("test", features, null); @@ -183,7 +183,7 @@ public void GetTreatments_WhenOneFeatureDoenstExist_ReturnsOnOffControl() var features = new List { alwaysOn, alwaysOff, alwaysControl }; - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); @@ -196,8 +196,7 @@ public void GetTreatments_WhenOneFeatureDoenstExist_ReturnsOnOffControl() Assert.AreEqual("on", result[alwaysOn]); Assert.AreEqual("control", result[alwaysControl]); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), - API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatments("test", features, null); @@ -213,7 +212,7 @@ public void GetTreatments_WhenOneFeatureDoenstExist_ReturnsOnOffControl() public void GetTreatmentsWithConfig_WhenClientIsNotReady_ReturnsControl() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); // Act. var result = client.GetTreatmentsWithConfig("key", new List()); @@ -225,8 +224,7 @@ public void GetTreatmentsWithConfig_WhenClientIsNotReady_ReturnsControl() Assert.IsNull(res.Value.Config); } - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatmentsWithConfig("key", new List()); @@ -243,7 +241,7 @@ public void GetTreatmentsWithConfig_WhenClientIsNotReady_ReturnsControl() public void GetTreatmentWithConfig_WhenClientIsNotReady_ReturnsControl() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); // Act. var result = client.GetTreatmentWithConfig("key", string.Empty); @@ -252,8 +250,7 @@ public void GetTreatmentWithConfig_WhenClientIsNotReady_ReturnsControl() Assert.AreEqual("control", result.Treatment); Assert.IsNull(result.Config); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatmentWithConfig("key", string.Empty); @@ -267,7 +264,7 @@ public void GetTreatmentWithConfig_WhenClientIsNotReady_ReturnsControl() public void GetTreatment_WhenClientIsNotReady_ReturnsControl() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); // Act. var result = client.GetTreatment("key", string.Empty); @@ -275,8 +272,7 @@ public void GetTreatment_WhenClientIsNotReady_ReturnsControl() // Assert. Assert.AreEqual("control", result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatment("key", string.Empty); @@ -290,7 +286,7 @@ public void GetTreatments_WhenClientIsNotReady_ReturnsControl() { // Arrange. config.CacheAdapterConfig.Host = "fake-host"; - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); // Act. var result = client.GetTreatments("key", new List()); @@ -301,7 +297,7 @@ public void GetTreatments_WhenClientIsNotReady_ReturnsControl() Assert.AreEqual("control", res.Value); } - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); result = client2.GetTreatments("key", new List()); @@ -317,7 +313,7 @@ public void GetTreatments_WhenClientIsNotReady_ReturnsControl() public void Track_WhenClientIsNotReady_ReturnsTrue() { // Arrange. - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); // Act. var result = client.Track("key", "traffic_type", "event_type"); @@ -325,8 +321,7 @@ public void Track_WhenClientIsNotReady_ReturnsTrue() // Assert. Assert.IsTrue(result); - var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), -API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client2 = new RedisClient(GetRedisClusterConfigurationOptions(), API_KEY); client2.BlockUntilReady(5000); // Act. @@ -343,9 +338,9 @@ public void FallbackTreatments_WhenFeatureDoesNotExist() var features = new List { alwaysOn, "feature", alwaysControl }; FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); + config.FallbackTreatments = fallbackTreatmentsConfiguration; - var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); @@ -380,10 +375,10 @@ public void FallbackTreatments_WhenClientNotReady() var features = new List { "feature" }; FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); config.CacheAdapterConfig.Host = "fake-host"; - var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator, _eventsManager); + config.FallbackTreatments = fallbackTreatmentsConfiguration; + var client = new RedisClient(config, API_KEY); //Act var result = client.GetTreatmentsWithConfig("test", features, null); @@ -403,9 +398,9 @@ public void FallbackTreatments_WhenExceptionOccurrs() var features = new List { "always_off" }; FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); + config.FallbackTreatments = fallbackTreatmentsConfiguration; - var client = new RedisClient(config, API_KEY, fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); @@ -434,7 +429,7 @@ public void FallbackTreatments_WhenExceptionOccurrs() public void Destroy() { //Arrange - var client = new RedisClient(config, API_KEY, _fallbackTreatmentCalculator, _eventsManager); + var client = new RedisClient(config, API_KEY); client.BlockUntilReady(5000); //Act diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs index deb27c04..49a16aee 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientForTesting.cs @@ -1,13 +1,10 @@ -using Splitio.Domain; -using Splitio.Services.Client.Classes; -using Splitio.Services.Common; -using Splitio.Services.Impressions.Classes; +using Splitio.Services.Client.Classes; namespace Splitio_Tests.Unit_Tests.Client { public class LocalhostClientForTesting : LocalhostClient { - public LocalhostClientForTesting(string filePath, FallbackTreatmentCalculator fallbackTreatmentCalculator) : base(new ConfigurationOptions { LocalhostFilePath = filePath }, fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig(), new EventDelivery())) + public LocalhostClientForTesting(string filePath) : base(new ConfigurationOptions { LocalhostFilePath = filePath }) { } } } diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs index 7bdfe24a..4609cd16 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs @@ -4,7 +4,6 @@ using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Shared.Classes; -using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Client { @@ -33,7 +32,7 @@ public LocalhostClientUnitTests() public void GetTreatmentShouldReturnControlIfSplitNotFound() { //Arrange - var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }, _fallbackTreatmentCalculator, _eventsManager); + var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }); //Act var result = splitClient.GetTreatment("test", "test"); @@ -46,7 +45,7 @@ public void GetTreatmentShouldReturnControlIfSplitNotFound() [DeploymentItem(@"Resources\test.splits")] public void GetTreatmentShouldRunAsSingleKeyUsingNullBucketingKey() { - var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }, _fallbackTreatmentCalculator, _eventsManager); + var splitClient = new LocalhostClient(new ConfigurationOptions { LocalhostFilePath = $"{rootFilePath}test.splits" }); splitClient.BlockUntilReady(1000); //Act @@ -62,7 +61,7 @@ public void GetTreatmentShouldRunAsSingleKeyUsingNullBucketingKey() public void TrackShouldNotStoreEvents() { //Arrange - var splitClient = new LocalhostClientForTesting($"{rootFilePath}test.splits", _fallbackTreatmentCalculator); + var splitClient = new LocalhostClientForTesting($"{rootFilePath}test.splits"); splitClient.BlockUntilReady(1000); //Act @@ -78,7 +77,7 @@ public void Destroy() { //Arrange var _factoryInstantiationsService = FactoryInstantiationsService.Instance(); - var splitClient = new LocalhostClientForTesting($"{rootFilePath}test.splits", _fallbackTreatmentCalculator); + var splitClient = new LocalhostClientForTesting($"{rootFilePath}test.splits"); //Act splitClient.BlockUntilReady(10000); diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs index ebacf349..9b377b34 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs @@ -2,6 +2,7 @@ using Moq; using Splitio.Domain; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Client.Classes; using Splitio.Services.Client.Interfaces; using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; @@ -40,7 +41,7 @@ public SplitClientAsyncTests() _syncManager = new Mock(); _telemetryEvaluationProducer = new Mock(); - _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, _impressionsLog.Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()), _telemetryEvaluationProducer.Object); + _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, _impressionsLog.Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, new ConfigurationOptions()); } #region GetTreatmentAsync @@ -1005,7 +1006,8 @@ public async Task FallbackTreatments_WhenFlagDoesNotExist() FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { splitName, new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); IEvaluator _evaluator = new Splitio.Services.Evaluator.Evaluator(_splitCache.Object, _splitter.Object, _telemetryEvaluationProducer.Object, fallbackTreatmentCalculator); - _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator, _impressionsManager.Object, _syncManager.Object, fallbackTreatmentCalculator, _telemetryEvaluationProducer.Object); + _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, + new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); _splitClient.BlockUntilReady(1000); string treatment = await _splitClient.GetTreatmentAsync("key", splitName); @@ -1077,13 +1079,13 @@ public async Task FallbackTreatments_WhenExceptionInClient() .Returns(true); FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { splitName, new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); _evaluator = new Mock(); _evaluator .Setup(mock => mock.EvaluateFeaturesAsync(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), true)) .Throws(); - _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, fallbackTreatmentCalculator, _telemetryEvaluationProducer.Object); + _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, + new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); _splitClient.BlockUntilReady(1000); string treatment = await _splitClient.GetTreatmentAsync("key", splitName); diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs index a44f94eb..2cc6936b 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs @@ -1,10 +1,8 @@ -using Splitio.Domain; -using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Cache.Interfaces; using Splitio.Services.Client.Classes; using Splitio.Services.Common; using Splitio.Services.Evaluator; using Splitio.Services.Events.Interfaces; -using Splitio.Services.Impressions.Classes; using Splitio.Services.Impressions.Interfaces; using Splitio.Services.InputValidation.Classes; using Splitio.Services.Shared.Interfaces; @@ -21,9 +19,9 @@ public SplitClientForTesting(IFeatureFlagCacheConsumer featureFlagCacheConsumer, IEvaluator evaluator, IImpressionsManager impressionsManager, ISyncManager syncManager, - FallbackTreatmentCalculator fallbackTreatmentCalculator, - ITelemetryEvaluationProducer telemetryEvaluationProducer) - : base("SplitClientForTesting", fallbackTreatmentCalculator, new EventsManager(new EventsManagerConfig(), new EventDelivery())) + ITelemetryEvaluationProducer telemetryEvaluationProducer, + ConfigurationOptions config) + : base("SplitClientForTesting", config) { _eventsLog = eventsLog; _impressionsLog = impressionsLog; diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs index 842b81a7..1b9c5636 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs @@ -45,7 +45,7 @@ public void TestInitialize() _syncManager = new Mock(); _telemetryEvaluationProducer = new Mock(); - _splitClientForTesting = new SplitClientForTesting(_splitCacheMock.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()), _telemetryEvaluationProducer.Object); + _splitClientForTesting = new SplitClientForTesting(_splitCacheMock.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, new ConfigurationOptions()); _splitClientForTesting.BlockUntilReady(1000); } @@ -779,7 +779,8 @@ public void FallbackTreatments_WhenFlagDoesNotExist() FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { splitName, new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); IEvaluator _evaluator = new Splitio.Services.Evaluator.Evaluator(_splitCache.Object, _splitter.Object, _telemetryEvaluationProducer.Object, fallbackTreatmentCalculator); - _splitClientForTesting = new SplitClientForTesting(_splitCache.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator, _impressionsManager.Object, _syncManager.Object, fallbackTreatmentCalculator, _telemetryEvaluationProducer.Object); + _splitClientForTesting = new SplitClientForTesting(_splitCache.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, + new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); _splitClientForTesting.BlockUntilReady(1000); string treatment = _splitClientForTesting.GetTreatment("key", splitName); @@ -851,13 +852,13 @@ public void FallbackTreatments_WhenExceptionInClient() .Returns(true); FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-global", "\"prop\":\"global\""), new Dictionary() { { splitName, new FallbackTreatment("off-local", "\"prop\":\"local\"") } }); - FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); _evaluatorMock = new Mock(); _evaluatorMock .Setup(mock => mock.EvaluateFeatures(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), true)) .Throws(); - _splitClientForTesting = new SplitClientForTesting(_splitCache.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, fallbackTreatmentCalculator, _telemetryEvaluationProducer.Object); + _splitClientForTesting = new SplitClientForTesting(_splitCache.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, + new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); _splitClientForTesting.BlockUntilReady(1000); string treatment = _splitClientForTesting.GetTreatment("key", splitName); diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index 049312b8..46424da1 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -53,7 +53,7 @@ public void Start_ShouldNotSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new Mock>().Object); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -72,7 +72,7 @@ public async Task Stop_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new Mock>().Object); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -96,7 +96,7 @@ public async Task Stop_ShouldSendImpressionsCount() public async Task ShouldSend2BulksOfImpressions() { var config = new ComponentConfig(6, 3); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig())); + var statusManager = new InMemoryReadinessGatesCache(new Mock>().Object); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 8e7110ca..2b845698 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -26,7 +26,7 @@ public class SelfRefreshingSegmentFetcherUnitTests public void InitializeSegmentNotExistent() { // Arrange - var gates = new InMemoryReadinessGatesCache(new Mock>().Object); + var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); gates.SetReady(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); diff --git a/tests/Splitio.TestSupport/Samples/SampleTest.cs b/tests/Splitio.TestSupport/Samples/SampleTest.cs index ecaee10a..9633110a 100644 --- a/tests/Splitio.TestSupport/Samples/SampleTest.cs +++ b/tests/Splitio.TestSupport/Samples/SampleTest.cs @@ -1,6 +1,4 @@ -using Moq; -using Splitio.Services.Client.Classes; -using Splitio.Services.Logger; +using Splitio.Services.Client.Classes; using Xunit; namespace Splitio.TestSupport.Samples @@ -11,7 +9,7 @@ public class SampleTest public SampleTest() { - splitClient = new SplitClientForTest(); + splitClient = new SplitClientForTest(new ConfigurationOptions()); } [Theory] diff --git a/tests/Splitio.TestSupport/SplitClientForTest.cs b/tests/Splitio.TestSupport/SplitClientForTest.cs index 363380c2..101d5210 100644 --- a/tests/Splitio.TestSupport/SplitClientForTest.cs +++ b/tests/Splitio.TestSupport/SplitClientForTest.cs @@ -10,8 +10,7 @@ public class SplitClientForTest : SplitClient { private readonly Dictionary _tests; - public SplitClientForTest() : base("SplitClientForTest", new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()), - new EventsManager(new EventsManagerConfig(), new EventDelivery())) + public SplitClientForTest(ConfigurationOptions config) : base("SplitClientForTest", config) { _tests = new Dictionary(); } From 5d3ac981002f7e594e5c50a13222b87e543360da Mon Sep 17 00:00:00 2001 From: Bilal Al-Shahwany <41021307+chillaq@users.noreply.github.com> Date: Fri, 26 Dec 2025 14:00:00 -0800 Subject: [PATCH 59/87] Update src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs Co-authored-by: Mauro Sanz <51236193+sanzmauro@users.noreply.github.com> --- .../Services/Cache/Classes/InMemoryReadinessGatesCache.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index 9d4b2e2d..f784fbbe 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -30,7 +30,6 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); - Thread.Sleep(1000); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); } From 855bb4fa0d66e1c7d5247d3a54c8e88b26f492d6 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 26 Dec 2025 14:12:05 -0800 Subject: [PATCH 60/87] fixed splitclient --- src/Splitio/Services/Client/Classes/SplitClient.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index ece0f641..1d00ef41 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -84,20 +84,13 @@ public event EventHandler SdkReady public event EventHandler SdkUpdate; public event EventHandler SdkTimedOut; - public event EventHandler SdkReady; - public event EventHandler SdkUpdate; - public event EventHandler SdkTimedOut; - protected SplitClient(string apikey, ConfigurationOptions options) { ApiKey = apikey; _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(options.FallbackTreatments); _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - - _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReadyEvent); - _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdateEvent); - _eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeoutEvent); - + RegisterEvents(); + _wrapperAdapter = WrapperAdapter.Instance(); _keyValidator = new KeyValidator(); _splitNameValidator = new SplitNameValidator(); From 3bb6e2ba02ebcdc210db7e31af311ada1b87c879 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 29 Dec 2025 19:17:28 -0800 Subject: [PATCH 61/87] added sorting events before notifying --- src/Splitio/Domain/EventManagerConfigData.cs | 1 + src/Splitio/Domain/EventsManagerConfig.cs | 44 ++++++++++++++++++- src/Splitio/Services/Common/EventsManager.cs | 9 ++-- .../Common/EventsManagerConfigTests.cs | 19 ++++++++ .../Unit Tests/Common/EventsManagerTests.cs | 27 +++++++++++- 5 files changed, 93 insertions(+), 7 deletions(-) diff --git a/src/Splitio/Domain/EventManagerConfigData.cs b/src/Splitio/Domain/EventManagerConfigData.cs index 1970f14c..a68295a5 100644 --- a/src/Splitio/Domain/EventManagerConfigData.cs +++ b/src/Splitio/Domain/EventManagerConfigData.cs @@ -9,5 +9,6 @@ public class EventManagerConfigData public Dictionary> Prerequisites { get; protected set; } public Dictionary> SuppressedBy { get; protected set; } public Dictionary ExecutionLimits { get; protected set; } + public HashSet EvaluationOrder { get; protected set; } } } diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index e5731caf..8783b9ff 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; +using System.Linq; namespace Splitio.Domain { public class EventsManagerConfig : EventManagerConfigData { - public EventsManagerConfig() + public EventsManagerConfig() { RequireAll = new Dictionary> { @@ -57,6 +58,47 @@ public EventsManagerConfig() { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; + + HashSet sortedEvents = new HashSet(); + foreach (SdkEvent sdkEvent in new List { SdkEvent.SdkReady, SdkEvent.SdkReadyTimeout, SdkEvent.SdkUpdate }) + { + sortedEvents = DFSRecursive(sdkEvent, sortedEvents); + } + + EvaluationOrder = sortedEvents; + } + + private HashSet DFSRecursive(SdkEvent sdkEvent, HashSet added) + { + if (added.Contains(sdkEvent)) return added; + + foreach (SdkEvent dependentEvent in GetDependencies(sdkEvent)) + { + added = DFSRecursive(dependentEvent, added); + } + + added.Add(sdkEvent); + + return added; + } + + private HashSet GetDependencies(SdkEvent sdkEvent) + { + HashSet dependencies = new HashSet(); + foreach (KeyValuePair> prerequisitesEvent in Prerequisites.Where(x => x.Key.Equals(sdkEvent))) + { + foreach (var prereqEvent in prerequisitesEvent.Value) + { + dependencies.Add(prereqEvent); + } + } + + foreach (KeyValuePair> suppressedEvent in SuppressedBy.Where(x => x.Value.Contains(sdkEvent))) + { + dependencies.Add(suppressedEvent.Key); + } + + return dependencies; } } } diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index bda64bd6..20be55e4 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -65,12 +65,11 @@ public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata) lock (_lock) { _logger.Debug($"EventsManager: Handling internal event {sdkInternalEvent}"); - - foreach (E sdkEvent in GetSdkEventIfApplicable(sdkInternalEvent)) + foreach (E sortedEvent in _managerConfig.EvaluationOrder.Where(x => GetSdkEventIfApplicable(sdkInternalEvent).Contains(x))) { - _logger.Debug($"EventsManager: Firing Sdk event {sdkEvent}"); - _eventDelivery.Deliver(sdkEvent, eventMetadata, GetEventHandler(sdkEvent)); - SetSdkEventTriggered(sdkEvent); + _logger.Debug($"EventsManager: Firing Sdk event {sortedEvent}"); + _eventDelivery.Deliver(sortedEvent, eventMetadata, GetEventHandler(sortedEvent)); + SetSdkEventTriggered(sortedEvent); } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index 899159b7..d8de94f3 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -41,6 +41,25 @@ public void BuildInstance() config.SuppressedBy.TryGetValue(SdkEvent.SdkReadyTimeout, out var require4); Assert.AreEqual(1, require3.Count); Assert.IsTrue(require4.Contains(SdkEvent.SdkReady)); + + int order = 0; + Assert.AreEqual(3, config.EvaluationOrder.Count); + foreach (var sdkEvent in config.EvaluationOrder) + { + order++; + switch (order) + { + case 1: + Assert.AreEqual(SdkEvent.SdkReadyTimeout, sdkEvent); + break; + case 2: + Assert.AreEqual(SdkEvent.SdkReady, sdkEvent); + break; + case 3: + Assert.AreEqual(SdkEvent.SdkUpdate, sdkEvent); + break; + } + } } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 5d662d98..d6d72f31 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -3,6 +3,7 @@ using Splitio.Services.Common; using System; using System.Collections.Generic; +using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Common { @@ -13,6 +14,7 @@ public class EventsManagerTests private bool SdkReadyFlag2 = false; private bool SdkTimedOutFlag = false; private bool SdkUpdateFlag = false; + private string FireFirst = ""; private EventMetadata eMetadata = null; public event EventHandler SdkReady; public event EventHandler SdkUpdate; @@ -119,7 +121,28 @@ public void TestFiringEvents() Assert.IsFalse(SdkUpdateFlag); } - void ResetAllVariables() + [TestMethod] + public void TestFireOrderEvents() + { + //Act + EventsManagerConfig config = new EventsManagerConfig(); + EventsManager eventsManager = new EventsManager(config, new EventDelivery()); + + SdkReady += sdkReady_callback; + SdkTimedOut += sdkTimedOut_callback; + + eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); + eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); + + ResetAllVariables(); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(new Dictionary())); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + Assert.IsTrue(SdkReadyFlag); + Assert.IsTrue(SdkTimedOutFlag); + Assert.AreEqual("SdkTimeout", FireFirst); + } + void ResetAllVariables() { SdkReadyFlag = false; SdkReadyFlag2 = false; @@ -146,6 +169,7 @@ private void sdkReady_callback(object sender, EventMetadata metadata) { SdkReadyFlag = true; eMetadata = metadata; + if (FireFirst.Equals("")) FireFirst = "SdkReady"; } private void sdkReady_callback2(object sender, EventMetadata metadata) @@ -158,6 +182,7 @@ private void sdkTimedOut_callback(object sender, EventMetadata metadata) { SdkTimedOutFlag = true; eMetadata = metadata; + if (FireFirst.Equals("")) FireFirst = "SdkTimeout"; } private void TriggerSdkReady(EventMetadata metaData) From 5b8b99a773e61b16be73452e1ef8fd12f306a529 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 30 Dec 2025 11:16:14 -0800 Subject: [PATCH 62/87] applied fallback validation --- .../Services/Client/Classes/RedisClient.cs | 3 ++- .../Services/Client/Classes/JSONFileClient.cs | 4 +-- .../Client/Classes/LocalhostClient.cs | 3 ++- .../Client/Classes/SelfRefreshingClient.cs | 3 ++- .../Services/Client/Classes/SplitClient.cs | 12 ++++++--- .../Classes/FallbackTreatmentsValidator.cs | 24 ++++++++++-------- .../IFallbackTreatmentsValidator.cs | 2 +- .../Client/SplitClientForTesting.cs | 3 ++- .../FallbackTreatmentsValidatorTests.cs | 16 ++++++------ .../Splitio.TestSupport/SplitClientForTest.cs | 5 ++-- .../BaseIntegrationTests.cs | 25 +++++++++++++++++++ 11 files changed, 69 insertions(+), 31 deletions(-) diff --git a/Splitio.Redis/Services/Client/Classes/RedisClient.cs b/Splitio.Redis/Services/Client/Classes/RedisClient.cs index f8027320..35274832 100644 --- a/Splitio.Redis/Services/Client/Classes/RedisClient.cs +++ b/Splitio.Redis/Services/Client/Classes/RedisClient.cs @@ -29,12 +29,13 @@ public class RedisClient : SplitClient private ConnectionPoolManager _connectionPoolManager; private IFeatureFlagCacheConsumer _featureFlagCacheConsumer; - public RedisClient(ConfigurationOptions config, string apiKey) : base(apiKey, config) + public RedisClient(ConfigurationOptions config, string apiKey) : base(apiKey) { _config = new RedisConfig(); ReadConfig(config); + BuildFallbackCalculator(config.FallbackTreatments); BuildRedisCache(); BuildTreatmentLog(config.ImpressionListener); diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index 5c2faeba..0c330e56 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -1,7 +1,6 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Events.Interfaces; using Splitio.Services.Impressions.Classes; @@ -33,7 +32,7 @@ public JSONFileClient(string splitsFilePath, ITrafficTypeValidator trafficTypeValidator = null, IImpressionsManager impressionsManager = null, IRuleBasedSegmentCache ruleBasedSegmentCache = null - ) : base("localhost", config) + ) : base("localhost") { _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), _eventsManager); var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), _eventsManager); @@ -53,6 +52,7 @@ public JSONFileClient(string splitsFilePath, parsedSplits.TryAdd(split.name, _splitParser.Parse(split, rbsCache)); } + BuildFallbackCalculator(config.FallbackTreatments); BuildFlagSetsFilter(new HashSet()); _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _eventsManager); _impressionsLog = impressionsLog; diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index 96495a1a..adabe05c 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -27,7 +27,7 @@ public class LocalhostClient : SplitClient private readonly object _lock = new object(); - public LocalhostClient(ConfigurationOptions configurationOptions) : base("localhost", configurationOptions) + public LocalhostClient(ConfigurationOptions configurationOptions) : base("localhost") { var configs = (LocalhostClientConfigurations)_configService.ReadConfig(configurationOptions, ConfigTypes.Localhost, _statusManager); @@ -44,6 +44,7 @@ public LocalhostClient(ConfigurationOptions configurationOptions) : base("localh _localhostFileService = new LocalhostFileService(); } + BuildFallbackCalculator(configurationOptions.FallbackTreatments); BuildFlagSetsFilter(new HashSet()); var splits = _localhostFileService.ParseSplitFile(_fullPath); diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 14fae995..e88f758f 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -52,10 +52,11 @@ public class SelfRefreshingClient : SplitClient private IRuleBasedSegmentCache _ruleBasedSegmentCache; private IUpdater _ruleBasedSegmentUpdater; - public SelfRefreshingClient(string apiKey, ConfigurationOptions config) : base(apiKey, config) + public SelfRefreshingClient(string apiKey, ConfigurationOptions config) : base(apiKey) { _config = (SelfRefreshingConfig)_configService.ReadConfig(config, ConfigTypes.InMemory); + BuildFallbackCalculator(config.FallbackTreatments); BuildFlagSetsFilter(_config.FlagSetsFilter); BuildSplitCache(); BuildSegmentCache(); diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 1d00ef41..6e04a324 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -39,7 +39,6 @@ public abstract class SplitClient : ISplitClient protected readonly IConfigService _configService; protected readonly IFlagSetsValidator _flagSetsValidator; protected readonly string ApiKey; - protected readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; protected ISplitManager _manager; protected IEventsLog _eventsLog; @@ -63,6 +62,8 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; + protected FallbackTreatmentCalculator _fallbackTreatmentCalculator; + public IEventsManager _eventsManager; private EventHandler SdkReadyEvent; public event EventHandler SdkReady @@ -84,10 +85,9 @@ public event EventHandler SdkReady public event EventHandler SdkUpdate; public event EventHandler SdkTimedOut; - protected SplitClient(string apikey, ConfigurationOptions options) + protected SplitClient(string apikey) { ApiKey = apikey; - _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(options.FallbackTreatments); _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); RegisterEvents(); @@ -445,6 +445,12 @@ protected void BuildFlagSetsFilter(HashSet sets) { _flagSetsFilter = new FlagSetsFilter(sets); } + + protected void BuildFallbackCalculator(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration) + { + FallbackTreatmentsValidator fallbackTreatmentsValidator = new FallbackTreatmentsValidator(); + _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration)); + } #endregion #region Private Async Methods diff --git a/src/Splitio/Services/InputValidation/Classes/FallbackTreatmentsValidator.cs b/src/Splitio/Services/InputValidation/Classes/FallbackTreatmentsValidator.cs index 0e88c9fe..b48675c5 100644 --- a/src/Splitio/Services/InputValidation/Classes/FallbackTreatmentsValidator.cs +++ b/src/Splitio/Services/InputValidation/Classes/FallbackTreatmentsValidator.cs @@ -15,7 +15,7 @@ public class FallbackTreatmentsValidator : IFallbackTreatmentsValidator private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(FallbackTreatmentsValidator)); - public FallbackTreatmentsConfiguration validate(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration, Enums.API method) + public FallbackTreatmentsConfiguration validate(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration) { FallbackTreatmentsConfiguration processedFallback = new FallbackTreatmentsConfiguration(); if (fallbackTreatmentsConfiguration == null) @@ -27,29 +27,33 @@ public FallbackTreatmentsConfiguration validate(FallbackTreatmentsConfiguration if (fallbackTreatmentsConfiguration.GlobalFallbackTreatment != null) { processedGlobalFallbackTreatment = new FallbackTreatment( - IsValidTreatment(fallbackTreatmentsConfiguration.GlobalFallbackTreatment.Treatment, method), + IsValidTreatment(fallbackTreatmentsConfiguration.GlobalFallbackTreatment.Treatment), fallbackTreatmentsConfiguration.GlobalFallbackTreatment.Config); + if (processedGlobalFallbackTreatment.Treatment == null) + { + processedGlobalFallbackTreatment = null; + } } if (fallbackTreatmentsConfiguration.ByFlagFallbackTreatment != null) { - processedByFlagFallbackTreatment = IsValidByFlagTreatment(fallbackTreatmentsConfiguration.ByFlagFallbackTreatment, method); + processedByFlagFallbackTreatment = IsValidByFlagTreatment(fallbackTreatmentsConfiguration.ByFlagFallbackTreatment); } return new FallbackTreatmentsConfiguration(processedGlobalFallbackTreatment, processedByFlagFallbackTreatment); } - public string IsValidTreatment(string name, Enums.API method) + public string IsValidTreatment(string name) { if (string.IsNullOrEmpty(name)) { - _log.Error($"{method}: you passed a null or empty treatment, fallback treatment must be a non-empty string"); + _log.Error($"FallbackTreatments: you passed a null or empty treatment, fallback treatment must be a non-empty string"); return null; } string trimmed = name.Trim(); if (!trimmed.Equals(name)) { - _log.Warn($"{method}: fallback treatment %s has extra whitespace, trimming"); + _log.Warn($"FallbackTreatments: fallback treatment %s has extra whitespace, trimming"); name = trimmed; } @@ -60,26 +64,26 @@ public string IsValidTreatment(string name, Enums.API method) if (!Regex.IsMatch(name, TreatmentMatcher, RegexOptions.None, TimeSpan.FromMilliseconds(100))) { - _log.Error($"{method}: you passed {name}, treatment must adhere to the regular expression {TreatmentMatcher}"); + _log.Error($"FallbackTreatments: you passed {name}, treatment must adhere to the regular expression {TreatmentMatcher}"); return null; } return name; } - public Dictionary IsValidByFlagTreatment(Dictionary byFlagTreatment, Enums.API method) + public Dictionary IsValidByFlagTreatment(Dictionary byFlagTreatment) { Dictionary result = new Dictionary(); foreach (var entry in byFlagTreatment) { - string featureName = new SplitNameValidator(_log).SplitNameIsValid(entry.Key, method).Value; + string featureName = new SplitNameValidator(_log).SplitNameIsValid(entry.Key, Enums.API.Split).Value; if (string.IsNullOrEmpty(featureName)) { continue; } FallbackTreatment fallbackTreatment = entry.Value; - string treatment = IsValidTreatment(fallbackTreatment.Treatment, method); + string treatment = IsValidTreatment(fallbackTreatment.Treatment); if (treatment != null) { result.Add(featureName, new FallbackTreatment(treatment, fallbackTreatment.Config)); diff --git a/src/Splitio/Services/InputValidation/Interfaces/IFallbackTreatmentsValidator.cs b/src/Splitio/Services/InputValidation/Interfaces/IFallbackTreatmentsValidator.cs index 498f6681..0fb71877 100644 --- a/src/Splitio/Services/InputValidation/Interfaces/IFallbackTreatmentsValidator.cs +++ b/src/Splitio/Services/InputValidation/Interfaces/IFallbackTreatmentsValidator.cs @@ -5,6 +5,6 @@ namespace Splitio.Services.InputValidation.Interfaces { public interface IFallbackTreatmentsValidator { - FallbackTreatmentsConfiguration validate(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration, Enums.API method); + FallbackTreatmentsConfiguration validate(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration); } } \ No newline at end of file diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs index 2cc6936b..b63ea971 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs @@ -21,8 +21,9 @@ public SplitClientForTesting(IFeatureFlagCacheConsumer featureFlagCacheConsumer, ISyncManager syncManager, ITelemetryEvaluationProducer telemetryEvaluationProducer, ConfigurationOptions config) - : base("SplitClientForTesting", config) + : base("SplitClientForTesting") { + BuildFallbackCalculator(config.FallbackTreatments); _eventsLog = eventsLog; _impressionsLog = impressionsLog; _blockUntilReadyService = blockUntilReadyService; diff --git a/tests/Splitio-tests/Unit Tests/InputValidation/FallbackTreatmentsValidatorTests.cs b/tests/Splitio-tests/Unit Tests/InputValidation/FallbackTreatmentsValidatorTests.cs index 0273d65d..98042b38 100644 --- a/tests/Splitio-tests/Unit Tests/InputValidation/FallbackTreatmentsValidatorTests.cs +++ b/tests/Splitio-tests/Unit Tests/InputValidation/FallbackTreatmentsValidatorTests.cs @@ -15,30 +15,30 @@ public void Works() FallbackTreatmentsValidator fallbackTreatmentsValidator = new FallbackTreatmentsValidator(); FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("12#2")); - Assert.AreEqual(null, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment).GlobalFallbackTreatment.Treatment); + Assert.AreEqual(null, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration).GlobalFallbackTreatment); fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration("12#2"); - Assert.AreEqual(null, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment).GlobalFallbackTreatment.Treatment); + Assert.AreEqual(null, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration).GlobalFallbackTreatment); fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration( new Dictionary() { { "flag", new FallbackTreatment("12#2") } }); - Assert.AreEqual(0, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment).ByFlagFallbackTreatment.Count); + Assert.AreEqual(0, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration).ByFlagFallbackTreatment.Count); fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration( new Dictionary() { { "flag", "12#2" } }); - Assert.AreEqual(0, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment).ByFlagFallbackTreatment.Count); + Assert.AreEqual(0, fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration).ByFlagFallbackTreatment.Count); fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration( new FallbackTreatment("on"), new Dictionary() { { "flag", new FallbackTreatment("off") } }); - var processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment); + var processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration); Assert.AreEqual("on", processed.GlobalFallbackTreatment.Treatment); processed.ByFlagFallbackTreatment.TryGetValue("flag", out FallbackTreatment fallbackTreatment); Assert.AreEqual("off", fallbackTreatment.Treatment); fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration("on", new Dictionary() { { "flag", new FallbackTreatment("off") } }); - processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment); + processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration); Assert.AreEqual("on", processed.GlobalFallbackTreatment.Treatment); processed.ByFlagFallbackTreatment.TryGetValue("flag", out FallbackTreatment fallbackTreatment2); Assert.AreEqual("off", fallbackTreatment2.Treatment); @@ -46,7 +46,7 @@ public void Works() fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration( new FallbackTreatment("on"), new Dictionary() { { "flag", "off" } }); - processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment); + processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration); Assert.AreEqual("on", processed.GlobalFallbackTreatment.Treatment); processed.ByFlagFallbackTreatment.TryGetValue("flag", out fallbackTreatment); Assert.AreEqual("off", fallbackTreatment.Treatment); @@ -54,7 +54,7 @@ public void Works() fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration( new FallbackTreatment("on"), new Dictionary() { { "flag", "off" } }); - processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration, Splitio.Enums.API.GetTreatment); + processed = fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration); Assert.AreEqual("on", processed.GlobalFallbackTreatment.Treatment); processed.ByFlagFallbackTreatment.TryGetValue("flag", out fallbackTreatment); Assert.AreEqual("off", fallbackTreatment.Treatment); diff --git a/tests/Splitio.TestSupport/SplitClientForTest.cs b/tests/Splitio.TestSupport/SplitClientForTest.cs index 101d5210..9f453fc1 100644 --- a/tests/Splitio.TestSupport/SplitClientForTest.cs +++ b/tests/Splitio.TestSupport/SplitClientForTest.cs @@ -1,6 +1,4 @@ using Splitio.Domain; -using Splitio.Services.Common; -using Splitio.Services.Impressions.Classes; using System.Collections.Generic; using System.Threading.Tasks; @@ -10,8 +8,9 @@ public class SplitClientForTest : SplitClient { private readonly Dictionary _tests; - public SplitClientForTest(ConfigurationOptions config) : base("SplitClientForTest", config) + public SplitClientForTest(ConfigurationOptions config) : base("SplitClientForTest") { + BuildFallbackCalculator(config.FallbackTreatments); _tests = new Dictionary(); } diff --git a/tests/Splitio.Tests.Common/BaseIntegrationTests.cs b/tests/Splitio.Tests.Common/BaseIntegrationTests.cs index 4bfa02db..0efa18c0 100644 --- a/tests/Splitio.Tests.Common/BaseIntegrationTests.cs +++ b/tests/Splitio.Tests.Common/BaseIntegrationTests.cs @@ -1155,6 +1155,31 @@ public void GetTreatmentsByFlagSet_WithWrongFlagSets() #region FallbackTreatments [TestMethod] + public void FallbackTreatmentsIgnored_WithInvalidConfig() + { + var features = new List { "feature2", "feature" }; + FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration = new FallbackTreatmentsConfiguration(new FallbackTreatment("on-gl^^obal", "\"prop\":\"global\""), new Dictionary() { { "feature", new FallbackTreatment("off-l###ocal", "\"prop\":\"local\"") } }); + var impressionListener = new IntegrationTestsImpressionListener(50); + var configurations = GetConfigurationOptions(impressionListener: impressionListener); + configurations.FallbackTreatments = fallbackTreatmentsConfiguration; + + var apikey = "base-apikey10"; + + var splitFactory = new SplitFactory(apikey, configurations); + var client = splitFactory.Client(); + + client.BlockUntilReady(10000); + + // Act. + var result = client.GetTreatment("nico_test", "feature"); + var result2 = client.GetTreatment("nico_test", "feature2"); + client.Destroy(); + + // Assert. + Assert.AreEqual("control", result); + Assert.AreEqual("control", result2); + } + [TestMethod] public void FallbackTreatments_WhenFeatureDoesNotExist() { var features = new List { "feature2", "feature" }; From c70e9d8d706d5e714148be3b0cbb45d11800b0f9 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 30 Dec 2025 11:37:13 -0800 Subject: [PATCH 63/87] polish --- src/Splitio/Services/Client/Classes/SplitClient.cs | 6 +++--- .../Unit Tests/Impressions/UniqueKeysTrackerTests.cs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 6e04a324..8d536d36 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,9 +63,9 @@ public abstract class SplitClient : ISplitClient protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; protected FallbackTreatmentCalculator _fallbackTreatmentCalculator; - - public IEventsManager _eventsManager; + protected IEventsManager _eventsManager; private EventHandler SdkReadyEvent; + public event EventHandler SdkReady { add @@ -73,7 +73,7 @@ public event EventHandler SdkReady SdkReadyEvent = (EventHandler)Delegate.Combine(SdkReadyEvent, value); if (_eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)) { - SdkReadyEvent.Invoke(this, null); + SdkReadyEvent.Invoke(this, new EventMetadata(new Dictionary())); } } diff --git a/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs index 6292b5d5..de2c485c 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs @@ -52,7 +52,7 @@ public async Task PeriodicTask_ShouldSendBulk() // Assert. Assert.IsTrue(_uniqueKeysTracker.Track("key-test", "feature-name-test")); - System.Threading.SpinWait.SpinUntil(() => _cache.Count == 0, TimeSpan.FromMilliseconds(2000)); + System.Threading.SpinWait.SpinUntil(() => _cache.IsEmpty, TimeSpan.FromMilliseconds(2000)); _senderAdapter.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Once); Assert.IsTrue(_uniqueKeysTracker.Track("key-test", "feature-name-test")); @@ -104,7 +104,7 @@ public void Track_WithFullSize_ShouldSendTwoBulk() Thread.Sleep(1000); Assert.IsTrue(_uniqueKeysTracker.Track("key-test-2", "feature-name-test-6")); - System.Threading.SpinWait.SpinUntil(() => _cache.Count==0, TimeSpan.FromMilliseconds(3000)); + System.Threading.SpinWait.SpinUntil(() => _cache.IsEmpty, TimeSpan.FromMilliseconds(3000)); _senderAdapter.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Exactly(2)); _cache.Clear(); @@ -144,7 +144,7 @@ public void Track_WithFullSize_ShouldSplitBulks() Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-5", "feature-name-test-2")); Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-6", "feature-name-test-2")); - System.Threading.SpinWait.SpinUntil(() => _cache2.Count == 0, TimeSpan.FromMilliseconds(3000)); + System.Threading.SpinWait.SpinUntil(() => _cache2.IsEmpty, TimeSpan.FromMilliseconds(3000)); _senderAdapter2.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Exactly(4)); _cache2.Clear(); From 70fb6afe63ad5edc5628412d784cf1769abc8b98 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Tue, 30 Dec 2025 20:48:17 -0800 Subject: [PATCH 64/87] reduce logging for events --- src/Splitio/Services/Common/EventDelivery.cs | 1 - src/Splitio/Services/Common/EventsManager.cs | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 38b04ffe..cc562399 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -13,7 +13,6 @@ public virtual void Deliver(E sdkEvent, M eventMetadata, Action handler) { if (handler != null) { - _logger.Debug($"EventDelivery: Triggering handle for Sdk Event {sdkEvent}"); try { handler.Invoke(eventMetadata); diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 20be55e4..68cdb526 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -64,7 +64,6 @@ public void NotifyInternalEvent(I sdkInternalEvent, M eventMetadata) { lock (_lock) { - _logger.Debug($"EventsManager: Handling internal event {sdkInternalEvent}"); foreach (E sortedEvent in _managerConfig.EvaluationOrder.Where(x => GetSdkEventIfApplicable(sdkInternalEvent).Contains(x))) { _logger.Debug($"EventsManager: Firing Sdk event {sortedEvent}"); @@ -93,7 +92,6 @@ public void UpdateSdkInternalEventStatus(I sdkInternalEvent, bool status) { _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, (_, oldValue) => status); - _logger.Debug($"EventsManager: Internal Event {sdkInternalEvent} status is updated to {status}"); } #endregion From 53917bc2250aa0f791a0a7a81cbadaf370435f42 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 2 Jan 2026 12:48:42 -0800 Subject: [PATCH 65/87] moved validation to config service --- Splitio.Redis/Services/Client/Classes/RedisClient.cs | 3 ++- src/Splitio/Domain/BaseConfig.cs | 1 + src/Splitio/Services/Client/Classes/LocalhostClient.cs | 2 +- .../Services/Client/Classes/SelfRefreshingClient.cs | 2 +- src/Splitio/Services/Client/Classes/SplitClient.cs | 3 +-- src/Splitio/Services/Shared/Classes/ConfigService.cs | 8 ++++++-- 6 files changed, 12 insertions(+), 7 deletions(-) diff --git a/Splitio.Redis/Services/Client/Classes/RedisClient.cs b/Splitio.Redis/Services/Client/Classes/RedisClient.cs index 35274832..d36a6cf4 100644 --- a/Splitio.Redis/Services/Client/Classes/RedisClient.cs +++ b/Splitio.Redis/Services/Client/Classes/RedisClient.cs @@ -35,7 +35,7 @@ public RedisClient(ConfigurationOptions config, string apiKey) : base(apiKey) ReadConfig(config); - BuildFallbackCalculator(config.FallbackTreatments); + BuildFallbackCalculator(_config.FallbackTreatments); BuildRedisCache(); BuildTreatmentLog(config.ImpressionListener); @@ -76,6 +76,7 @@ private void ReadConfig(ConfigurationOptions config) _config.FlagSetsInvalid = baseConfig.FlagSetsInvalid; _config.Mode = config.Mode; _config.FromCacheAdapterConfig(config.CacheAdapterConfig); + _config.FallbackTreatments = baseConfig.FallbackTreatments; } private void BuildRedisCache() diff --git a/src/Splitio/Domain/BaseConfig.cs b/src/Splitio/Domain/BaseConfig.cs index f4f2edf9..a43ffa94 100644 --- a/src/Splitio/Domain/BaseConfig.cs +++ b/src/Splitio/Domain/BaseConfig.cs @@ -11,6 +11,7 @@ public class BaseConfig public ImpressionsMode ImpressionsMode { get; set; } public HashSet FlagSetsFilter { get; set; } public int FlagSetsInvalid { get; set; } + public FallbackTreatmentsConfiguration FallbackTreatments { get; set; } // Bloom Filter public int BfExpectedElements { get; set; } diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index adabe05c..76e425b8 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -44,7 +44,7 @@ public LocalhostClient(ConfigurationOptions configurationOptions) : base("localh _localhostFileService = new LocalhostFileService(); } - BuildFallbackCalculator(configurationOptions.FallbackTreatments); + BuildFallbackCalculator(configs.FallbackTreatments); BuildFlagSetsFilter(new HashSet()); var splits = _localhostFileService.ParseSplitFile(_fullPath); diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index e88f758f..1eb77975 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -56,7 +56,7 @@ public SelfRefreshingClient(string apiKey, ConfigurationOptions config) : base(a { _config = (SelfRefreshingConfig)_configService.ReadConfig(config, ConfigTypes.InMemory); - BuildFallbackCalculator(config.FallbackTreatments); + BuildFallbackCalculator(_config.FallbackTreatments); BuildFlagSetsFilter(_config.FlagSetsFilter); BuildSplitCache(); BuildSegmentCache(); diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 8d536d36..9fdf9c90 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -448,8 +448,7 @@ protected void BuildFlagSetsFilter(HashSet sets) protected void BuildFallbackCalculator(FallbackTreatmentsConfiguration fallbackTreatmentsConfiguration) { - FallbackTreatmentsValidator fallbackTreatmentsValidator = new FallbackTreatmentsValidator(); - _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsValidator.validate(fallbackTreatmentsConfiguration)); + _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); } #endregion diff --git a/src/Splitio/Services/Shared/Classes/ConfigService.cs b/src/Splitio/Services/Shared/Classes/ConfigService.cs index 6e9a684e..df2e7a58 100644 --- a/src/Splitio/Services/Shared/Classes/ConfigService.cs +++ b/src/Splitio/Services/Shared/Classes/ConfigService.cs @@ -19,6 +19,7 @@ public class ConfigService : IConfigService private readonly IWrapperAdapter _wrapperAdapter; private readonly IFlagSetsValidator _flagSetsValidator; private readonly ISdkMetadataValidator _sdkMetadataValidator; + private readonly FallbackTreatmentsValidator _fallbackTreatmentsValidator = new FallbackTreatmentsValidator(); public ConfigService(IWrapperAdapter wrapperAdapter, IFlagSetsValidator flagSetsValidator, @@ -59,6 +60,7 @@ public static LocalhostClientConfigurations ReadLocalhostConfig(ConfigurationOpt } localhostClientConfigurations.FileSync = fileSync; + localhostClientConfigurations.FallbackTreatments = new FallbackTreatmentsValidator().validate(config.FallbackTreatments); return localhostClientConfigurations; } @@ -124,7 +126,8 @@ public SelfRefreshingConfig ReadInMemoryConfig(ConfigurationOptions config) OnDemandFetchMaxRetries = 10, OnDemandFetchRetryDelayMs = 50, ProxyHost = config.ProxyHost, - ProxyPort = config.ProxyPort + ProxyPort = config.ProxyPort, + FallbackTreatments = baseConfig.FallbackTreatments }; selfRefreshingConfig.ImpressionsMode = config.ImpressionsMode ?? ImpressionsMode.Optimized; @@ -151,7 +154,8 @@ private BaseConfig ReadBaseConfig(ConfigurationOptions config, ConfigTypes type) UniqueKeysCacheMaxSize = 50000, ImpressionsCounterCacheMaxSize = 50000, FlagSetsFilter = flagSetsResult.FlagSets, - FlagSetsInvalid = flagSetsResult.Invalid + FlagSetsInvalid = flagSetsResult.Invalid, + FallbackTreatments = _fallbackTreatmentsValidator.validate(config.FallbackTreatments) }; } From 7ae1aab19cfb74e47707374c9e174b90e5d4eeb4 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 5 Jan 2026 11:18:00 -0800 Subject: [PATCH 66/87] changed fallback calc param to interface --- .../Services/Client/Classes/SplitClient.cs | 2 +- src/Splitio/Services/Evaluator/Evaluator.cs | 16 +++---- .../Shared/Classes/ClientExtensionService.cs | 8 ++-- src/Splitio/Util/Helper.cs | 8 ++-- .../Client/SplitClientAsyncTests.cs | 33 +++++++++++--- .../Client/SplitClientForTesting.cs | 5 ++- .../Unit Tests/Client/SplitClientUnitTests.cs | 44 ++++++++++++++----- .../Impressions/UniqueKeysTrackerTests.cs | 6 +-- 8 files changed, 84 insertions(+), 38 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 9fdf9c90..77f03e44 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -62,7 +62,7 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; - protected FallbackTreatmentCalculator _fallbackTreatmentCalculator; + protected IFallbackTreatmentCalculator _fallbackTreatmentCalculator; protected IEventsManager _eventsManager; private EventHandler SdkReadyEvent; diff --git a/src/Splitio/Services/Evaluator/Evaluator.cs b/src/Splitio/Services/Evaluator/Evaluator.cs index ee4040c4..d46958c7 100644 --- a/src/Splitio/Services/Evaluator/Evaluator.cs +++ b/src/Splitio/Services/Evaluator/Evaluator.cs @@ -3,7 +3,7 @@ using Splitio.Enums.Extensions; using Splitio.Services.Cache.Interfaces; using Splitio.Services.EngineEvaluator; -using Splitio.Services.Impressions.Classes; +using Splitio.Services.Impressions.Interfaces; using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using Splitio.Telemetry.Storages; @@ -23,12 +23,12 @@ public class Evaluator : IEvaluator private readonly ISplitter _splitter; private readonly IFeatureFlagCacheConsumer _featureFlagCacheConsumer; private readonly ITelemetryEvaluationProducer _telemetryEvaluationProducer; - private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; + private readonly IFallbackTreatmentCalculator _fallbackTreatmentCalculator; public Evaluator(IFeatureFlagCacheConsumer featureFlagCache, ISplitter splitter, ITelemetryEvaluationProducer telemetryEvaluationProducer, - FallbackTreatmentCalculator fallbackTreatmentCalculator) + IFallbackTreatmentCalculator fallbackTreatmentCalculator) { _featureFlagCacheConsumer = featureFlagCache; _splitter = splitter; @@ -63,7 +63,7 @@ public List EvaluateFeatures(API method, Key key, List _log.Error($"{method}: Something went wrong evaluation feature: {feature}", e); _telemetryEvaluationProducer?.RecordException(method.ConvertToMethodEnum()); - treatmentsForFeatures.Add(Helper.checkFallbackTreatment(feature, Labels.Exception, true, _fallbackTreatmentCalculator)); + treatmentsForFeatures.Add(Helper.CheckFallbackTreatment(feature, Labels.Exception, true, _fallbackTreatmentCalculator)); } } @@ -137,7 +137,7 @@ public async Task> EvaluateFeaturesAsync(API method, Key k if (_telemetryEvaluationProducer != null) await _telemetryEvaluationProducer.RecordExceptionAsync(method.ConvertToMethodEnum()); - treatmentsForFeatures.Add(Helper.checkFallbackTreatment(feature, Labels.Exception, true, _fallbackTreatmentCalculator)); + treatmentsForFeatures.Add(Helper.CheckFallbackTreatment(feature, Labels.Exception, true, _fallbackTreatmentCalculator)); } } @@ -345,7 +345,7 @@ private TreatmentResult EvaluateFeatureException(Exception e, string featureName { _log.Error($"Exception caught getting treatment for feature flag: {featureName}", e); - return Helper.checkFallbackTreatment(featureName, Labels.Exception, true, _fallbackTreatmentCalculator); + return Helper.CheckFallbackTreatment(featureName, Labels.Exception, true, _fallbackTreatmentCalculator); } private List EvaluateFeaturesException(Exception e, List featureNames) @@ -356,7 +356,7 @@ private List EvaluateFeaturesException(Exception e, List ReturnControl(List featureFlagNames, string foreach (var item in featureFlagNames) { - toReturn.Add(Helper.checkFallbackTreatment(item, label, true, _fallbackTreatmentCalculator)); + toReturn.Add(Helper.CheckFallbackTreatment(item, label, true, _fallbackTreatmentCalculator)); } return toReturn; diff --git a/src/Splitio/Util/Helper.cs b/src/Splitio/Util/Helper.cs index 84dc8dda..bcaa4557 100644 --- a/src/Splitio/Util/Helper.cs +++ b/src/Splitio/Util/Helper.cs @@ -1,6 +1,6 @@ using Splitio.CommonLibraries; using Splitio.Domain; -using Splitio.Services.Impressions.Classes; +using Splitio.Services.Impressions.Interfaces; using Splitio.Services.Logger; using Splitio.Telemetry.Domain.Enums; using Splitio.Telemetry.Storages; @@ -62,7 +62,7 @@ public static List> ChunkBy(List source, int chunkSize) .ToList(); } - public static TreatmentResult checkFallbackTreatment(string featureName, string label, bool exception, FallbackTreatmentCalculator fallbackTreatmentCalculator) + public static TreatmentResult CheckFallbackTreatment(string featureName, string label, bool exception, IFallbackTreatmentCalculator fallbackTreatmentCalculator) { FallbackTreatment fallbackTreatment = fallbackTreatmentCalculator.resolve(featureName, label); return new TreatmentResult(featureName, @@ -70,12 +70,12 @@ public static TreatmentResult checkFallbackTreatment(string featureName, string fallbackTreatment.Treatment, false, null, - getFallbackConfig(fallbackTreatment), + GetFallbackConfig(fallbackTreatment), exception ); } - public static string getFallbackConfig(FallbackTreatment fallbackTreatment) + public static string GetFallbackConfig(FallbackTreatment fallbackTreatment) { if (fallbackTreatment.Config != null) { diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs index 9b377b34..5fd49eff 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientAsyncTests.cs @@ -2,8 +2,6 @@ using Moq; using Splitio.Domain; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Client.Classes; -using Splitio.Services.Client.Interfaces; using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Evaluator; @@ -29,6 +27,7 @@ public class SplitClientAsyncTests private readonly Mock _impressionsManager; private readonly Mock _syncManager; private Mock _telemetryEvaluationProducer; + private readonly Mock _fallbackTreatmentCalculation; private SplitClientForTesting _splitClient; public SplitClientAsyncTests() { @@ -40,8 +39,8 @@ public SplitClientAsyncTests() _impressionsManager = new Mock(); _syncManager = new Mock(); _telemetryEvaluationProducer = new Mock(); - - _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, _impressionsLog.Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, new ConfigurationOptions()); + _fallbackTreatmentCalculation = new Mock(); + _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, _impressionsLog.Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, _fallbackTreatmentCalculation.Object); } #region GetTreatmentAsync @@ -52,6 +51,9 @@ public async Task GetTreatment_WithNullKey_ReturnsControl() _blockUntilReadyService .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); // Act var result = await _splitClient.GetTreatmentAsync((string)null, string.Empty); @@ -67,6 +69,9 @@ public async Task GetTreatment_WhenNameDoesntExist_ReturnsControl() _blockUntilReadyService .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); _evaluator .Setup(mock => mock.EvaluateFeaturesAsync(It.IsAny(), It.IsAny(), It.IsAny>(), It.IsAny>(), true)) @@ -90,6 +95,10 @@ public async Task GetTreatment_WhenExist_ReturnsOn() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + _evaluator .Setup(mock => mock.EvaluateFeaturesAsync(It.IsAny(), It.IsAny(), new List() { "feature_flag_test" }, It.IsAny>(), true)) .ReturnsAsync(new List { new TreatmentResult("feature_flag_test", Labels.DefaultRule, "on", false, 1000, null) }); @@ -120,6 +129,10 @@ public async Task GetTreatments_WithEmptyKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var results = await _splitClient.GetTreatmentsAsync(string.Empty, new List { string.Empty }); @@ -249,6 +262,10 @@ public async Task GetTreatmentWithConfig_WithEmptyKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var result = await _splitClient.GetTreatmentWithConfigAsync(string.Empty, string.Empty); @@ -587,6 +604,10 @@ public async Task GetTreatmentsWithConfig_WithEmptyKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var results = await _splitClient.GetTreatmentsWithConfigAsync(string.Empty, new List { string.Empty }); @@ -1007,7 +1028,7 @@ public async Task FallbackTreatments_WhenFlagDoesNotExist() FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); IEvaluator _evaluator = new Splitio.Services.Evaluator.Evaluator(_splitCache.Object, _splitter.Object, _telemetryEvaluationProducer.Object, fallbackTreatmentCalculator); _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, - new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); + fallbackTreatmentCalculator); _splitClient.BlockUntilReady(1000); string treatment = await _splitClient.GetTreatmentAsync("key", splitName); @@ -1085,7 +1106,7 @@ public async Task FallbackTreatments_WhenExceptionInClient() .Throws(); _splitClient = new SplitClientForTesting(_splitCache.Object, _eventsLog.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, - new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); + new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration)); _splitClient.BlockUntilReady(1000); string treatment = await _splitClient.GetTreatmentAsync("key", splitName); diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs index b63ea971..fe11a14e 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientForTesting.cs @@ -3,6 +3,7 @@ using Splitio.Services.Common; using Splitio.Services.Evaluator; using Splitio.Services.Events.Interfaces; +using Splitio.Services.Impressions.Classes; using Splitio.Services.Impressions.Interfaces; using Splitio.Services.InputValidation.Classes; using Splitio.Services.Shared.Interfaces; @@ -20,10 +21,10 @@ public SplitClientForTesting(IFeatureFlagCacheConsumer featureFlagCacheConsumer, IImpressionsManager impressionsManager, ISyncManager syncManager, ITelemetryEvaluationProducer telemetryEvaluationProducer, - ConfigurationOptions config) + IFallbackTreatmentCalculator fallbackTreatmentCalculator) : base("SplitClientForTesting") { - BuildFallbackCalculator(config.FallbackTreatments); + _fallbackTreatmentCalculator = fallbackTreatmentCalculator; _eventsLog = eventsLog; _impressionsLog = impressionsLog; _blockUntilReadyService = blockUntilReadyService; diff --git a/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs index 1b9c5636..baa0f2df 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SplitClientUnitTests.cs @@ -1,13 +1,7 @@ -using AnyOfTypes; -using HandlebarsDotNet.Features; -using Microsoft.CSharp.RuntimeBinder; -using Microsoft.OpenApi.Any; -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Splitio.Domain; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Client.Classes; -using Splitio.Services.Client.Interfaces; using Splitio.Services.Common; using Splitio.Services.EngineEvaluator; using Splitio.Services.Evaluator; @@ -32,6 +26,7 @@ public class SplitClientUnitTests private Mock _impressionsManager; private Mock _syncManager; private Mock _telemetryEvaluationProducer; + private Mock _fallbackTreatmentCalculation; private SplitClientForTesting _splitClientForTesting; [TestInitialize] @@ -44,8 +39,9 @@ public void TestInitialize() _impressionsManager = new Mock(); _syncManager = new Mock(); _telemetryEvaluationProducer = new Mock(); + _fallbackTreatmentCalculation = new Mock(); - _splitClientForTesting = new SplitClientForTesting(_splitCacheMock.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, new ConfigurationOptions()); + _splitClientForTesting = new SplitClientForTesting(_splitCacheMock.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, _fallbackTreatmentCalculation.Object); _splitClientForTesting.BlockUntilReady(1000); } @@ -59,6 +55,10 @@ public void GetTreatment_ShouldReturnControl_WithNullKey() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var result = _splitClientForTesting.GetTreatment((string)null, string.Empty); @@ -74,6 +74,10 @@ public void GetTreatment_ShouldReturnControl_WithNullMatchingKey() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var result = _splitClientForTesting.GetTreatment(new Key(null, string.Empty), string.Empty); @@ -89,6 +93,10 @@ public void GetTreatment_ShouldReturnControl_WithNullMatchingAndBucketingKey() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var result = _splitClientForTesting.GetTreatment(new Key(null, null), string.Empty); @@ -293,6 +301,10 @@ public void GetTreatmentWithConfig_WithEmptyKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var result = _splitClientForTesting.GetTreatmentWithConfig(string.Empty, string.Empty); @@ -309,6 +321,10 @@ public void GetTreatmentWithConfig_WithNullKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var result = _splitClientForTesting.GetTreatmentWithConfig((Key)null, string.Empty); @@ -618,6 +634,10 @@ public void GetTreatmentsWithConfig_WithEmptyKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var results = _splitClientForTesting.GetTreatmentsWithConfig(string.Empty, new List { string.Empty }); @@ -637,6 +657,10 @@ public void GetTreatmentsWithConfig_WithNullKey_ShouldReturnControl() .Setup(mock => mock.IsSdkReady()) .Returns(true); + _fallbackTreatmentCalculation + .Setup(mock => mock.resolve(It.IsAny(), It.IsAny())) + .Returns(new FallbackTreatment("control")); + // Act var results = _splitClientForTesting.GetTreatmentsWithConfig((Key)null, new List { string.Empty }); @@ -780,7 +804,7 @@ public void FallbackTreatments_WhenFlagDoesNotExist() FallbackTreatmentCalculator fallbackTreatmentCalculator = new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration); IEvaluator _evaluator = new Splitio.Services.Evaluator.Evaluator(_splitCache.Object, _splitter.Object, _telemetryEvaluationProducer.Object, fallbackTreatmentCalculator); _splitClientForTesting = new SplitClientForTesting(_splitCache.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluator, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, - new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); + fallbackTreatmentCalculator); _splitClientForTesting.BlockUntilReady(1000); string treatment = _splitClientForTesting.GetTreatment("key", splitName); @@ -858,7 +882,7 @@ public void FallbackTreatments_WhenExceptionInClient() .Throws(); _splitClientForTesting = new SplitClientForTesting(_splitCache.Object, _eventsLogMock.Object, new Mock().Object, _blockUntilReadyService.Object, _evaluatorMock.Object, _impressionsManager.Object, _syncManager.Object, _telemetryEvaluationProducer.Object, - new ConfigurationOptions { FallbackTreatments = fallbackTreatmentsConfiguration }); + new FallbackTreatmentCalculator(fallbackTreatmentsConfiguration)); _splitClientForTesting.BlockUntilReady(1000); string treatment = _splitClientForTesting.GetTreatment("key", splitName); diff --git a/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs index de2c485c..01512f51 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/UniqueKeysTrackerTests.cs @@ -52,7 +52,7 @@ public async Task PeriodicTask_ShouldSendBulk() // Assert. Assert.IsTrue(_uniqueKeysTracker.Track("key-test", "feature-name-test")); - System.Threading.SpinWait.SpinUntil(() => _cache.IsEmpty, TimeSpan.FromMilliseconds(2000)); + System.Threading.SpinWait.SpinUntil(() => _cache.IsEmpty, TimeSpan.FromMilliseconds(5000)); _senderAdapter.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Once); Assert.IsTrue(_uniqueKeysTracker.Track("key-test", "feature-name-test")); @@ -104,7 +104,7 @@ public void Track_WithFullSize_ShouldSendTwoBulk() Thread.Sleep(1000); Assert.IsTrue(_uniqueKeysTracker.Track("key-test-2", "feature-name-test-6")); - System.Threading.SpinWait.SpinUntil(() => _cache.IsEmpty, TimeSpan.FromMilliseconds(3000)); + System.Threading.SpinWait.SpinUntil(() => _cache.IsEmpty, TimeSpan.FromMilliseconds(5000)); _senderAdapter.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Exactly(2)); _cache.Clear(); @@ -144,7 +144,7 @@ public void Track_WithFullSize_ShouldSplitBulks() Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-5", "feature-name-test-2")); Assert.IsTrue(_uniqueKeysTracker2.Track("key-test-6", "feature-name-test-2")); - System.Threading.SpinWait.SpinUntil(() => _cache2.IsEmpty, TimeSpan.FromMilliseconds(3000)); + System.Threading.SpinWait.SpinUntil(() => _cache2.IsEmpty, TimeSpan.FromMilliseconds(5000)); _senderAdapter2.Verify(mock => mock.RecordUniqueKeysAsync(It.IsAny>()), Times.Exactly(4)); _cache2.Clear(); From a0533f7f4d034bb07c463a7096756310e2ba88cc Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 23 Jan 2026 10:04:18 -0800 Subject: [PATCH 67/87] updated metadata with Sdk event type --- src/Splitio/Constants/Constants.cs | 7 --- src/Splitio/Domain/EventMetadata.cs | 41 +++------------- src/Splitio/Domain/SdkEventType.cs | 9 ++++ .../Classes/InMemoryReadinessGatesCache.cs | 4 +- .../Classes/InMemoryRuleBasedSegmentCache.cs | 5 +- .../Cache/Classes/InMemorySegmentCache.cs | 7 ++- .../Cache/Classes/InMemorySplitCache.cs | 5 +- .../Services/Client/Classes/SplitClient.cs | 2 +- .../SelfRefreshingBlockUntilReadyService.cs | 3 +- .../InMemory/RuleBasedSegmentCacheTests.cs | 8 +--- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 6 +-- .../Cache/InMemory/SegmentCacheTests.cs | 10 ++-- .../Cache/InMemory/SplitCacheAsyncTests.cs | 16 +++---- .../Cache/InMemory/SplitCacheTests.cs | 16 +++---- .../Client/SdkReadinessGatesUnitTests.cs | 2 +- .../Unit Tests/Common/EventDeliveryTests.cs | 16 +------ .../Unit Tests/Common/EventMetadataTests.cs | 48 ++----------------- .../Unit Tests/Common/EventsManagerTests.cs | 45 ++++++++--------- ...lfRefreshingBlockUntilReadyServiceTests.cs | 2 +- 19 files changed, 76 insertions(+), 176 deletions(-) create mode 100644 src/Splitio/Domain/SdkEventType.cs diff --git a/src/Splitio/Constants/Constants.cs b/src/Splitio/Constants/Constants.cs index 318606c6..0c382a1f 100644 --- a/src/Splitio/Constants/Constants.cs +++ b/src/Splitio/Constants/Constants.cs @@ -61,11 +61,4 @@ public static class ApiVersions public static string Spec1_1 => "1.1"; public static string LatestFlagsSpec => "1.3"; } - - public static class EventMetadataKeys - { - public static string Flags => "flags"; - public static string Segments => "segments"; - public static string RuleBasedSegments => "ruleBasedSegments"; - } } diff --git a/src/Splitio/Domain/EventMetadata.cs b/src/Splitio/Domain/EventMetadata.cs index 67441887..2070bb14 100644 --- a/src/Splitio/Domain/EventMetadata.cs +++ b/src/Splitio/Domain/EventMetadata.cs @@ -6,44 +6,17 @@ namespace Splitio.Domain { public class EventMetadata { - private readonly Dictionary _data; + private List _names; + private SdkEventType _type; - public EventMetadata(Dictionary data) + public EventMetadata(SdkEventType type, List names) { - _data = Santize(data); + _type = type; + _names = names; } - public Dictionary GetData() { return _data; } - - public List GetKeys() { return _data.Keys.ToList(); } - - public List GetValues() { return _data.Values.ToList(); } - - public bool ContainKey(string key) - { - return _data.ContainsKey(key); - } - - private static Dictionary Santize(Dictionary data) - { - Dictionary santizedData = new Dictionary(); - foreach (var item in data.Where(x => ValueIsValid(x.Value))) - { - santizedData.Add(item.Key, item.Value); - } - - return santizedData; - } - - private static bool ValueIsValid(object value) - { - if (!(value is null) && (PropertiesValidator.IsNumeric(value) || (value is bool) || (value is string) || (value is List))) - { - return true; - } - - return false; - } + public List GetNames() { return _names; } + public SdkEventType GetEventType() { return _type; } } } diff --git a/src/Splitio/Domain/SdkEventType.cs b/src/Splitio/Domain/SdkEventType.cs new file mode 100644 index 00000000..c8ba6f92 --- /dev/null +++ b/src/Splitio/Domain/SdkEventType.cs @@ -0,0 +1,9 @@ + +namespace Splitio.Domain +{ + public enum SdkEventType + { + SegmentsUpdate, + FlagsUpdate + } +} diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index f784fbbe..2c07b868 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -1,7 +1,6 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; -using System.Collections.Generic; using System.Threading; namespace Splitio.Services.Client.Classes @@ -30,8 +29,7 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, - new EventMetadata(new Dictionary())); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); } public void SetDestroy() diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 998e419a..86efecd2 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -1,5 +1,4 @@ -using Splitio.Constants; -using Splitio.Domain; +using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; using System.Collections.Concurrent; @@ -65,7 +64,7 @@ public void Update(List toAdd, List toRemove, long til SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.RuleBasedSegments, toNotify } })); + new EventMetadata(SdkEventType.SegmentsUpdate, toNotify)); } public void SetChangeNumber(long changeNumber) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 1a687722..63a2b002 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -1,5 +1,4 @@ -using Splitio.Constants; -using Splitio.Domain; +using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; using Splitio.Services.Logger; @@ -36,7 +35,7 @@ public void AddToSegment(string segmentName, List segmentKeys) segment.AddKeys(segmentKeys); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } })); + new EventMetadata(SdkEventType.SegmentsUpdate, new List())); } public void RemoveFromSegment(string segmentName, List segmentKeys) @@ -45,7 +44,7 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) { segment.RemoveKeys(segmentKeys); _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Segments, segmentName } })); + new EventMetadata(SdkEventType.SegmentsUpdate, new List())); } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index 1a99fd8c..acb0cb46 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Threading.Tasks; using Splitio.Services.Common; -using Splitio.Constants; namespace Splitio.Services.Cache.Classes { @@ -80,7 +79,7 @@ public void Update(List toAdd, List toRemove, long till) SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, - new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, eventsFlags } })); + new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)); } public void SetChangeNumber(long changeNumber) @@ -153,7 +152,7 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, - new EventMetadata(new Dictionary { { EventMetadataKeys.Flags, new List { { featureFlag.name } } } })); + new EventMetadata(SdkEventType.FlagsUpdate, new List { { featureFlag.name } })); } diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 77f03e44..18544cb0 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -73,7 +73,7 @@ public event EventHandler SdkReady SdkReadyEvent = (EventHandler)Delegate.Combine(SdkReadyEvent, value); if (_eventsManager.EventAlreadyTriggered(SdkEvent.SdkReady)) { - SdkReadyEvent.Invoke(this, new EventMetadata(new Dictionary())); + SdkReadyEvent.Invoke(this, null); } } diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index 5edb873c..b62c505f 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -36,8 +36,7 @@ public void BlockUntilReady(int blockMilisecondsUntilReady) if (!_statusManager.WaitUntilReady(blockMilisecondsUntilReady)) { - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, - new EventMetadata(new Dictionary())); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); _telemetryInitProducer.RecordBURTimeout(); throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady} milliseconds"); } diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index 023b5ce8..62102f57 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -162,7 +162,7 @@ public void Update_ShouldNotifyEvent() SdkUpdate += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); // Act SdkUpdateFlag = false; @@ -170,11 +170,7 @@ public void Update_ShouldNotifyEvent() // Assert Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.RuleBasedSegments)); - List rbsegments = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.RuleBasedSegments]; - Assert.IsTrue(rbsegments.Count == 3); - Assert.IsTrue(rbsegments.Contains("segment-to-add")); - Assert.IsTrue(rbsegments.Contains("segment-to-remove")); + Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index dcaf47d0..d0a15f8b 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -64,7 +64,7 @@ public async Task NotifyEventsTest() SdkUpdate += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); //Act SdkUpdateFlag = false; @@ -72,9 +72,7 @@ public async Task NotifyEventsTest() //Assert Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); - string segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; - Assert.AreEqual(segmentName, segment); + Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index 689d109b..20de160e 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -114,7 +114,7 @@ public void NotifyEventsTest() SdkUpdate += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); // Act SdkUpdateFlag = false; @@ -122,9 +122,7 @@ public void NotifyEventsTest() //Assert Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); - string segment = (string) eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; - Assert.AreEqual(segmentName, segment); + Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); // Act SdkUpdateFlag = false; @@ -133,9 +131,7 @@ public void NotifyEventsTest() //Assert Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Segments)); - segment = (string)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Segments]; - Assert.AreEqual(segmentName, segment); + Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index 985b6275..f2bf14dd 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -196,7 +196,7 @@ public async Task NotifyUpdateEventTest() SdkUpdate += sdkUpdate_callback; _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); SdkUpdateFlag = false; _cache.Update(toAdd, new List(), -1); @@ -207,12 +207,11 @@ public async Task NotifyUpdateEventTest() // Assert. Assert.AreEqual(5, result.Count); Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); - List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; - Assert.IsTrue(flags.Count == 5); + Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); + Assert.IsTrue(eMetadata.GetNames().Count == 5); for (int i = 1; i <= 5; i++) { - Assert.IsTrue(flags.Contains($"feature-flag-{i}")); + Assert.IsTrue(eMetadata.GetNames().Contains($"feature-flag-{i}")); } SdkUpdateFlag = false; @@ -220,10 +219,9 @@ public async Task NotifyUpdateEventTest() _cache.Kill(123, "feature-flag-1", "off"); Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); - flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; - Assert.IsTrue(flags.Count == 1); - Assert.IsTrue(flags.Contains($"feature-flag-1")); + Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); + Assert.IsTrue(eMetadata.GetNames().Count == 1); + Assert.IsTrue(eMetadata.GetNames().Contains($"feature-flag-1")); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index 651f66ee..d0938016 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -253,7 +253,7 @@ public void NotifyUpdateEventTest() SdkUpdate += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); // Act. SdkUpdateFlag = false; @@ -261,10 +261,9 @@ public void NotifyUpdateEventTest() // Assert. Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); - List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; - Assert.IsTrue(flags.Count == 1); - Assert.IsTrue(flags.Contains(splitName)); + Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); + Assert.IsTrue(eMetadata.GetNames().Count == 1); + Assert.IsTrue(eMetadata.GetNames().Contains(splitName)); // Act. SdkUpdateFlag = false; @@ -273,10 +272,9 @@ public void NotifyUpdateEventTest() // Assert. Assert.IsTrue(SdkUpdateFlag); - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); - flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; - Assert.IsTrue(flags.Count == 1); - Assert.IsTrue(flags.Contains(splitName)); + Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); + Assert.IsTrue(eMetadata.GetNames().Count == 1); + Assert.IsTrue(eMetadata.GetNames().Contains(splitName)); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index d17713b5..d6d90ff2 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -40,7 +40,7 @@ public void TestFireReadyEvent() // Assert. Assert.IsTrue(SdkReadyFlag); - Assert.AreEqual(0, eMetadata.GetData().Count); + Assert.AreEqual(null, eMetadata); } private void sdkReady_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index 1619f9d1..f12c5abc 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -17,23 +17,9 @@ public void TestFiringEvents() //Act EventDelivery eventDelivery = new EventDelivery(); - Dictionary metaData = new Dictionary - { - { "flags", new List {{ "flag1" }} } - }; - - eventDelivery.Deliver(SdkEvent.SdkReady, new EventMetadata(metaData), sdkReady_callback); + eventDelivery.Deliver(SdkEvent.SdkReady, null, sdkReady_callback); Assert.IsTrue(SdkReady); - VerifyMetadata(eMetadata); - } - - void VerifyMetadata(EventMetadata eMetdata) - { - Assert.IsTrue(eMetadata.ContainKey("flags")); - List flags = (List)eMetadata.GetData()["flags"]; - Assert.IsTrue(flags.Count == 1); - Assert.IsTrue(flags.Contains("flag1")); } private void sdkReady_callback(EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs index 057eb708..d94cf0bb 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventMetadataTests.cs @@ -9,53 +9,15 @@ public class EventMetadataTests { [TestMethod] - public void InstanceWithSantizeInput() + public void InstanceWithInput() { - //Arrange - Dictionary data = new Dictionary - { - { "updatedFlags", new List() { { "feature1" } } }, - { "sdkTimeout", 10 }, - { "boolValue", true }, - { "strValue", "value" } - }; - - //Act - var result = new EventMetadata(data); - - //Assert - Assert.AreEqual(4, result.GetKeys().Count); - result.GetData().TryGetValue("updatedFlags", out var features); - List featureList = (List)features; - result.GetData().TryGetValue("sdkTimeout", out var timeout); - result.GetData().TryGetValue("boolValue", out var bvalue); - result.GetData().TryGetValue("strValue", out var svalue); - - Assert.AreEqual(10, timeout); - Assert.IsTrue((bool)bvalue); - Assert.AreEqual("value", svalue); - Assert.IsTrue(featureList.Count == 1); - Assert.IsTrue(featureList.Contains("feature1")); - Assert.IsTrue(result.ContainKey("updatedFlags")); - } - - [TestMethod] - public void SantizeNullInput() - { - //Arrange - Dictionary data = new Dictionary - { - { "wrong-null", null }, - { "wrong-other", new List() }, - { "updatedFlags", new List() { { "feature1" } } } - }; - //Act - var result = new EventMetadata(data); + var result = new EventMetadata(SdkEventType.FlagsUpdate, new List() { { "feature1" } }); //Assert - Assert.AreEqual(1, result.GetKeys().Count); - Assert.IsTrue(result.ContainKey("updatedFlags")); + Assert.AreEqual(1, result.GetNames().Count); + Assert.AreEqual(SdkEventType.FlagsUpdate, result.GetEventType()); + Assert.IsTrue(result.GetNames().Contains("feature1")); } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index d6d72f31..28f41e65 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -3,7 +3,6 @@ using Splitio.Services.Common; using System; using System.Collections.Generic; -using WireMock.Pact.Models.V2; namespace Splitio_Tests.Unit_Tests.Common { @@ -39,82 +38,82 @@ public void TestFiringEvents() eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsFalse(SdkTimedOutFlag); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsFalse(SdkTimedOutFlag); // not fired as it is not registered yet eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsTrue(SdkTimedOutFlag); - VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReadyFlag); Assert.IsTrue(SdkReadyFlag2); Assert.IsFalse(SdkUpdateFlag); Assert.IsFalse(SdkTimedOutFlag); - VerifyMetadata(eMetadata); ResetAllVariables(); eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsFalse(SdkTimedOutFlag); // not fired as suppressed by sdkReady ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); + Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); VerifyMetadata(eMetadata); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); - VerifyMetadata(eMetadata); + Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); - VerifyMetadata(eMetadata); + Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); + Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); VerifyMetadata(eMetadata); eventsManager.Unregister(SdkEvent.SdkUpdate); eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(metaData)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); @@ -135,8 +134,8 @@ public void TestFireOrderEvents() eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, new EventMetadata(new Dictionary())); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, new EventMetadata(new Dictionary())); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); + eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); Assert.IsTrue(SdkReadyFlag); Assert.IsTrue(SdkTimedOutFlag); @@ -153,10 +152,8 @@ void ResetAllVariables() void VerifyMetadata(EventMetadata eMetdata) { - Assert.IsTrue(eMetadata.ContainKey(Splitio.Constants.EventMetadataKeys.Flags)); - List flags = (List)eMetadata.GetData()[Splitio.Constants.EventMetadataKeys.Flags]; - Assert.IsTrue(flags.Count == 1); - Assert.IsTrue(flags.Contains("flag1")); + Assert.IsTrue(eMetdata.GetNames().Count == 1); + Assert.IsTrue(eMetdata.GetNames().Contains("flag1")); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index 6f63501d..ef00e607 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -39,7 +39,7 @@ public void TestFireTimedOutEvent() // Assert. Assert.IsTrue(SdkTimedOutFlag); - Assert.AreEqual(0, eMetadata.GetData().Count); + Assert.AreEqual(null, eMetadata); } private void sdkTimeout_callback(object sender, EventMetadata metadata) From f781b25579f4ec21ff230bfea75688bf47efcb9d Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 23 Jan 2026 10:09:46 -0800 Subject: [PATCH 68/87] removed list of rbsegments in notification --- .../Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 86efecd2..4f10ee00 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -49,22 +49,19 @@ public long GetChangeNumber() // Producer public void Update(List toAdd, List toRemove, long till) { - List toNotify = new List(); foreach (var rbSegment in toAdd) { _cache.AddOrUpdate(rbSegment.Name, rbSegment, (key, oldValue) => rbSegment); - toNotify.Add(rbSegment.Name); } foreach (var name in toRemove) { _cache.TryRemove(name, out var _); - toNotify.Add(name); } SetChangeNumber(till); _eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, - new EventMetadata(SdkEventType.SegmentsUpdate, toNotify)); + new EventMetadata(SdkEventType.SegmentsUpdate, new List())); } public void SetChangeNumber(long changeNumber) From cc5d5bfb42e863deca76d349f260162c5ef736ab Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 23 Jan 2026 14:36:19 -0800 Subject: [PATCH 69/87] added InternalEventsTask to use a queue for firing internal events --- src/Splitio/Domain/SdkEventNotification.cs | 16 +++++ .../Classes/InMemoryReadinessGatesCache.cs | 10 +-- .../Classes/InMemoryRuleBasedSegmentCache.cs | 10 +-- .../Cache/Classes/InMemorySegmentCache.cs | 12 ++-- .../Cache/Classes/InMemorySplitCache.cs | 12 ++-- .../Services/Client/Classes/JSONFileClient.cs | 6 +- .../Client/Classes/LocalhostClient.cs | 2 +- .../Client/Classes/SelfRefreshingClient.cs | 6 +- .../Services/Client/Classes/SplitClient.cs | 8 ++- src/Splitio/Services/Common/EventDelivery.cs | 24 ++++---- .../Services/Tasks/IInternalEventsTask.cs | 12 ++++ .../Services/Tasks/InternalEventsTask.cs | 61 +++++++++++++++++++ .../SelfRefreshingSegmentFetcherTests.cs | 4 +- .../TargetingRulesFetcherTests.cs | 27 ++++---- .../InMemory/RuleBasedSegmentCacheTests.cs | 9 ++- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 9 ++- .../Cache/InMemory/SegmentCacheTests.cs | 29 +++++---- .../Cache/InMemory/SplitCacheAsyncTests.cs | 9 ++- .../Cache/InMemory/SplitCacheTests.cs | 44 +++++++------ .../Client/SdkReadinessGatesUnitTests.cs | 15 ++++- .../Unit Tests/Common/EventDeliveryTests.cs | 4 +- .../Unit Tests/Common/EventsManagerTests.cs | 19 +++--- .../Impressions/ImpressionsCounterTests.cs | 17 ++++-- .../UserDefinedSegmentMatcherAsyncTests.cs | 34 +++++------ .../UserDefinedSegmentMatcherTests.cs | 34 +++++------ .../SelfRefreshingSegmentFetcherUnitTests.cs | 7 ++- .../SelfRefreshingSegmentUnitTests.cs | 10 +-- .../Tasks/InternalEvenstTaskTests.cs | 39 ++++++++++++ .../EventSourceClientTests.cs | 4 +- 29 files changed, 343 insertions(+), 150 deletions(-) create mode 100644 src/Splitio/Domain/SdkEventNotification.cs create mode 100644 src/Splitio/Services/Tasks/IInternalEventsTask.cs create mode 100644 src/Splitio/Services/Tasks/InternalEventsTask.cs create mode 100644 tests/Splitio-tests/Unit Tests/Tasks/InternalEvenstTaskTests.cs diff --git a/src/Splitio/Domain/SdkEventNotification.cs b/src/Splitio/Domain/SdkEventNotification.cs new file mode 100644 index 00000000..737496e7 --- /dev/null +++ b/src/Splitio/Domain/SdkEventNotification.cs @@ -0,0 +1,16 @@ +using Splitio.Domain; + +namespace Splitio.Services.EventSource.Workers +{ + public class SdkEventNotification + { + public SdkInternalEvent SdkInternalEvent { get; set; } + public EventMetadata EventMetadata { get; set; } + + public SdkEventNotification(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) + { + SdkInternalEvent = sdkInternalEvent; + EventMetadata = eventMetadata; + } + } +} diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index 2c07b868..6252411c 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -1,6 +1,6 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; +using Splitio.Services.Tasks; using System.Threading; namespace Splitio.Services.Client.Classes @@ -9,11 +9,11 @@ public class InMemoryReadinessGatesCache : IStatusManager { private readonly CountdownEvent _sdkReady = new CountdownEvent(1); private readonly CountdownEvent _sdkDestroyed = new CountdownEvent(1); - private readonly IEventsManager _eventsManager; + private readonly IInternalEventsTask _internalEventsTask; - public InMemoryReadinessGatesCache(IEventsManager eventsManager) + public InMemoryReadinessGatesCache(IInternalEventsTask internalEventsTask) { - _eventsManager = eventsManager; + _internalEventsTask = internalEventsTask; } public bool IsReady() @@ -29,7 +29,7 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); + _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null); } public void SetDestroy() diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 4f10ee00..28b47ff2 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -1,6 +1,6 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; +using Splitio.Services.Tasks; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -11,15 +11,15 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache { private readonly ConcurrentDictionary _cache; private long _changeNumber; - private readonly IEventsManager _eventsManager; + private readonly IInternalEventsTask _internalEventsTask; public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, - IEventsManager eventsManger, + IInternalEventsTask internalEventsTask, long changeNumber = -1) { _cache = cache; _changeNumber = changeNumber; - _eventsManager = eventsManger; + _internalEventsTask = internalEventsTask; } #region Sync Methods @@ -60,7 +60,7 @@ public void Update(List toAdd, List toRemove, long til } SetChangeNumber(till); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, + _internalEventsTask.AddToQueue(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 63a2b002..3dd3195a 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -1,8 +1,8 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -14,12 +14,12 @@ public class InMemorySegmentCache : ISegmentCache private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemorySegmentCache)); private readonly ConcurrentDictionary _segments; - private readonly IEventsManager _eventsManager; + private readonly IInternalEventsTask _internalEventsTask; - public InMemorySegmentCache(ConcurrentDictionary segments, IEventsManager eventsManger) + public InMemorySegmentCache(ConcurrentDictionary segments, IInternalEventsTask internalEventsTask) { _segments = segments; - _eventsManager = eventsManger; + _internalEventsTask = internalEventsTask; } #region Methods Sync @@ -34,7 +34,7 @@ public void AddToSegment(string segmentName, List segmentKeys) } segment.AddKeys(segmentKeys); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, + _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); } @@ -43,7 +43,7 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) if (_segments.TryGetValue(segmentName, out Segment segment)) { segment.RemoveKeys(segmentKeys); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, + _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index acb0cb46..29530591 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Splitio.Services.Common; +using Splitio.Services.Tasks; namespace Splitio.Services.Cache.Classes { @@ -19,12 +19,12 @@ public class InMemorySplitCache : IFeatureFlagCache private readonly ConcurrentDictionary _featureFlags; private readonly ConcurrentDictionary _trafficTypes; private readonly ConcurrentDictionary> _flagSets; - private readonly IEventsManager _eventsManager; + private readonly IInternalEventsTask _internalEventsTask; private long _changeNumber; public InMemorySplitCache(ConcurrentDictionary featureFlags, - IFlagSetsFilter flagSetsFilter, IEventsManager eventsManger, + IFlagSetsFilter flagSetsFilter, IInternalEventsTask internalEventsTask, long changeNumber = -1) { _featureFlags = featureFlags; @@ -32,7 +32,7 @@ public InMemorySplitCache(ConcurrentDictionary featureFlags _changeNumber = changeNumber; _trafficTypes = new ConcurrentDictionary(); _flagSets = new ConcurrentDictionary>(); - _eventsManager = eventsManger; + _internalEventsTask = internalEventsTask; if (!_featureFlags.IsEmpty) { @@ -78,7 +78,7 @@ public void Update(List toAdd, List toRemove, long till) } SetChangeNumber(till); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, + _internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)); } @@ -151,7 +151,7 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) featureFlag.changeNumber = changeNumber; _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); - _eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, + _internalEventsTask.AddToQueue(SdkInternalEvent.FlagKilledNotification, new EventMetadata(SdkEventType.FlagsUpdate, new List { { featureFlag.name } })); } diff --git a/src/Splitio/Services/Client/Classes/JSONFileClient.cs b/src/Splitio/Services/Client/Classes/JSONFileClient.cs index 0c330e56..34bd7194 100644 --- a/src/Splitio/Services/Client/Classes/JSONFileClient.cs +++ b/src/Splitio/Services/Client/Classes/JSONFileClient.cs @@ -34,8 +34,8 @@ public JSONFileClient(string splitsFilePath, IRuleBasedSegmentCache ruleBasedSegmentCache = null ) : base("localhost") { - _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), _eventsManager); - var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), _eventsManager); + _segmentCache = segmentCacheInstance ?? new InMemorySegmentCache(new ConcurrentDictionary(), _internalEventsTask); + var rbsCache = ruleBasedSegmentCache ?? new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), _internalEventsTask); var segmentFetcher = new JSONFileSegmentFetcher(segmentsFilePath, _segmentCache); var splitChangeFetcher = new JSONFileSplitChangeFetcher(splitsFilePath); @@ -54,7 +54,7 @@ public JSONFileClient(string splitsFilePath, BuildFallbackCalculator(config.FallbackTreatments); BuildFlagSetsFilter(new HashSet()); - _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _eventsManager); + _featureFlagCache = featureFlagCacheInstance ?? new InMemorySplitCache(new ConcurrentDictionary(parsedSplits), _flagSetsFilter, _internalEventsTask); _impressionsLog = impressionsLog; _eventsLog = eventsLog; _trafficTypeValidator = trafficTypeValidator; diff --git a/src/Splitio/Services/Client/Classes/LocalhostClient.cs b/src/Splitio/Services/Client/Classes/LocalhostClient.cs index 76e425b8..92cb305f 100644 --- a/src/Splitio/Services/Client/Classes/LocalhostClient.cs +++ b/src/Splitio/Services/Client/Classes/LocalhostClient.cs @@ -48,7 +48,7 @@ public LocalhostClient(ConfigurationOptions configurationOptions) : base("localh BuildFlagSetsFilter(new HashSet()); var splits = _localhostFileService.ParseSplitFile(_fullPath); - _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); + _featureFlagCache = new InMemorySplitCache(splits, _flagSetsFilter, _internalEventsTask); if (configs.FileSync != null) diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 1eb77975..54dfc606 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -88,17 +88,17 @@ public SelfRefreshingClient(string apiKey, ConfigurationOptions config) : base(a #region Private Methods private void BuildSplitCache() { - _featureFlagCache = new InMemorySplitCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _flagSetsFilter, _eventsManager); + _featureFlagCache = new InMemorySplitCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _flagSetsFilter, _internalEventsTask); } private void BuildSegmentCache() { - _segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _eventsManager); + _segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _internalEventsTask); } private void BuildRuleBasedSegmentCache() { - _ruleBasedSegmentCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _eventsManager); + _ruleBasedSegmentCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(_config.ConcurrencyLevel, InitialCapacity), _internalEventsTask); } private void BuildTelemetryStorage() diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 18544cb0..267a9c02 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -64,6 +64,7 @@ public abstract class SplitClient : ISplitClient protected IFlagSetsFilter _flagSetsFilter; protected IFallbackTreatmentCalculator _fallbackTreatmentCalculator; protected IEventsManager _eventsManager; + protected IInternalEventsTask _internalEventsTask; private EventHandler SdkReadyEvent; public event EventHandler SdkReady @@ -89,6 +90,8 @@ protected SplitClient(string apikey) { ApiKey = apikey; _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + _internalEventsTask = new InternalEventsTask(_eventsManager, new SplitQueue()); + _internalEventsTask.Start(); RegisterEvents(); _wrapperAdapter = WrapperAdapter.Instance(); @@ -99,7 +102,7 @@ protected SplitClient(string apikey) _factoryInstantiationsService = FactoryInstantiationsService.Instance(); _flagSetsValidator = new FlagSetsValidator(); _configService = new ConfigService(_wrapperAdapter, _flagSetsValidator, new SdkMetadataValidator()); - _statusManager = new InMemoryReadinessGatesCache(_eventsManager); + _statusManager = new InMemoryReadinessGatesCache(_internalEventsTask); _tasksManager = new TasksManager(_statusManager); } @@ -317,7 +320,7 @@ public virtual async Task DestroyAsync() if (_statusManager.IsDestroyed()) return; _log.Info(Messages.InitDestroy); - + _internalEventsTask.Stop(); _factoryInstantiationsService.Decrease(ApiKey); _statusManager.SetDestroy(); await _syncManager.ShutdownAsync(); @@ -332,6 +335,7 @@ public virtual void Destroy() _log.Info(Messages.InitDestroy); + _internalEventsTask.Stop(); _factoryInstantiationsService.Decrease(ApiKey); _statusManager.SetDestroy(); _syncManager.Shutdown(); diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index cc562399..1ba68871 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -1,7 +1,7 @@ -using Splitio.Domain; -using Splitio.Services.Logger; +using Splitio.Services.Logger; using Splitio.Services.Shared.Classes; using System; +using System.Threading; namespace Splitio.Services.Common { @@ -9,18 +9,18 @@ public class EventDelivery : IEventDelivery { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); - public virtual void Deliver(E sdkEvent, M eventMetadata, Action handler) + public void Deliver(E sdkEvent, M eventMetadata, Action callbackAction) { - if (handler != null) + try { - try - { - handler.Invoke(eventMetadata); - } - catch (Exception e) - { - _logger.Error($"EventDelivery: Failed to run event {sdkEvent} handler {e.Message}", e); - } + Thread eventCallbackThread = new Thread(() => callbackAction(eventMetadata)); + eventCallbackThread.Start(); + } + catch (Exception ex) + { + if (ex is OperationCanceledException) return; + + _logger.Debug($"EventDelivery worker Execute exception", ex); } } } diff --git a/src/Splitio/Services/Tasks/IInternalEventsTask.cs b/src/Splitio/Services/Tasks/IInternalEventsTask.cs new file mode 100644 index 00000000..47552f7e --- /dev/null +++ b/src/Splitio/Services/Tasks/IInternalEventsTask.cs @@ -0,0 +1,12 @@ +using Splitio.Domain; +using System.Threading.Tasks; + +namespace Splitio.Services.Tasks +{ + public interface IInternalEventsTask + { + Task AddToQueue(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata); + void Start(); + void Stop(); + } +} diff --git a/src/Splitio/Services/Tasks/InternalEventsTask.cs b/src/Splitio/Services/Tasks/InternalEventsTask.cs new file mode 100644 index 00000000..5e654dbf --- /dev/null +++ b/src/Splitio/Services/Tasks/InternalEventsTask.cs @@ -0,0 +1,61 @@ +using Splitio.Domain; +using Splitio.Services.Common; +using Splitio.Services.EventSource.Workers; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; +using System; +using System.Threading.Tasks; + +namespace Splitio.Services.Tasks +{ + public class InternalEventsTask : BaseWorker, IQueueObserver, IInternalEventsTask + { + IEventsManager _eventsManager; + private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("InternalEventsTask"); + private readonly SplitQueue _queue; + + public InternalEventsTask(IEventsManager eventsManager, + SplitQueue internalEventsQueue) : base("InternalEventsTask", WrapperAdapter.Instance().GetLogger(typeof(InternalEventsTask))) + { + _eventsManager = eventsManager; + _queue = internalEventsQueue; + _queue.AddObserver(this); + } + + public async Task AddToQueue(SdkInternalEvent sdkInternalEvent, EventMetadata eventMetadata) + { + try + { + if (!_running) + { + _logger.Error("InternalEventTask Worker not running."); + return; + } + + _logger.Debug($"InternalEventTask: Add to queue: {sdkInternalEvent}"); + await _queue.EnqueueAsync(new SdkEventNotification(sdkInternalEvent, eventMetadata)); + } + catch (Exception ex) + { + _logger.Error($"InternalEventTask error AddToQueue: {ex.Message}"); + } + } + + public async Task Notify() + { + try + { + if (!_queue.TryDequeue(out SdkEventNotification sdkEventDto)) return; + + _logger.Debug($"InternalEventTask: SdkEvent dequeue: {sdkEventDto.SdkInternalEvent}"); + _eventsManager.NotifyInternalEvent(sdkEventDto.SdkInternalEvent, sdkEventDto.EventMetadata); + } + catch (Exception ex) + { + if (ex is OperationCanceledException) return; + + _logger.Debug($"InternalEventTask worker Execute exception", ex); + } + } + } +} diff --git a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs index 70839600..c06d2d69 100644 --- a/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/SelfRefreshingSegmentFetcherTests.cs @@ -3,6 +3,7 @@ using Splitio.Services.Cache.Classes; using Splitio.Services.Common; using Splitio.Services.SegmentFetcher.Classes; +using Splitio.Services.Tasks; using System.Collections.Concurrent; namespace Splitio_Tests.Integration_Tests @@ -28,7 +29,8 @@ public void ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new Splitio.Services.Shared.Classes.SplitQueue()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index 7d4e8f53..a1fdde68 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -39,14 +39,15 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() { //Arrange var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); - var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); + var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), internalEventsTask); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); - var gates = new InMemoryReadinessGatesCache(eventsManager); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -85,14 +86,15 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAll { //Arrange var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); - var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); + var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), internalEventsTask); var segmentFetcher = new JSONFileSegmentFetcher($"{rootFilePath}segment_payed.json", segmentCache); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging_4.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); - var gates = new InMemoryReadinessGatesCache(eventsManager); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -142,17 +144,18 @@ public async Task ExecuteGetWithoutResults() var sdkSegmentApiClient = new SegmentSdkApiClient(httpClient, telemetryStorage, baseUrl); var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var gates = new InMemoryReadinessGatesCache(eventsManager); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(4, segmentsQueue); segmentsQueue.AddObserver(worker); var segmentsTask = taskManager.NewPeriodicTask(Splitio.Enums.Task.SegmentsFetcher, 3000); var segmentFetcher = new SelfRefreshingSegmentFetcher(apiSegmentChangeFetcher, segmentCache, segmentsQueue, segmentsTask, gates); - var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), eventsManager); + var rbsCache = new InMemoryRuleBasedSegmentCache(new ConcurrentDictionary(), internalEventsTask); var splitParser = new FeatureFlagParser(segmentCache, segmentFetcher); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, eventsManager); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 3000); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); var rbsParser = new RuleBasedSegmentParser(segmentCache, segmentFetcher); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index 62102f57..159d4eb8 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -2,9 +2,12 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; +using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace Splitio_Tests.Unit_Tests.Cache.InMemory @@ -16,6 +19,7 @@ public class RuleBasedSegmentCacheTests private EventsManager _eventsManager; private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; + private IInternalEventsTask _internalEventsTask; public event EventHandler SdkUpdate; public event EventHandler SdkReady; @@ -24,7 +28,9 @@ public void Setup() { var cache = new ConcurrentDictionary(); _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - _segmentCache = new InMemoryRuleBasedSegmentCache(cache, _eventsManager); + _internalEventsTask = new InternalEventsTask(_eventsManager, new SplitQueue()); + _internalEventsTask.Start(); + _segmentCache = new InMemoryRuleBasedSegmentCache(cache, _internalEventsTask); } [TestMethod] @@ -167,6 +173,7 @@ public void Update_ShouldNotifyEvent() // Act SdkUpdateFlag = false; _segmentCache.Update(new List { segmentToAdd, segmentToRemove }, new List { segmentToRemove.Name }, till); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); // Assert Assert.IsTrue(SdkUpdateFlag); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index d0a15f8b..f6e36fed 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -3,9 +3,12 @@ using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; +using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; namespace Splitio_Tests.Unit_Tests.Cache @@ -17,6 +20,7 @@ public class SegmentCacheAsyncTests private EventsManager _eventsManager; private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; + private IInternalEventsTask _internalEventsTask; public event EventHandler SdkUpdate; public event EventHandler SdkReady; @@ -24,7 +28,9 @@ public SegmentCacheAsyncTests() { var segments = new ConcurrentDictionary(); _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - _cache = new InMemorySegmentCache(segments, _eventsManager); + _internalEventsTask = new InternalEventsTask(_eventsManager, new SplitQueue()); + _internalEventsTask.Start(); + _cache = new InMemorySegmentCache(segments, _internalEventsTask); } [TestMethod] @@ -69,6 +75,7 @@ public async Task NotifyEventsTest() //Act SdkUpdateFlag = false; _cache.AddToSegment(segmentName, new List { "abcd", "zzzzf" }); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); //Assert Assert.IsTrue(SdkUpdateFlag); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs index 20de160e..c2977121 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheTests.cs @@ -3,9 +3,12 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Common; +using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Threading; namespace Splitio_Tests.Unit_Tests.Cache { @@ -21,8 +24,8 @@ public class SegmentCacheTests public void RegisterSegmentTest() { //Arrange - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var keys = new List { "abcd", "1234" }; var segmentName = "test"; @@ -38,8 +41,8 @@ public void RegisterSegmentTest() public void IsNotInSegmentTest() { //Arrange - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -55,8 +58,8 @@ public void IsNotInSegmentTest() public void IsInSegmentWithInexistentSegmentTest() { //Arrange - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); //Act var result = segmentCache.IsInSegment("test", "abcd"); @@ -69,8 +72,8 @@ public void IsInSegmentWithInexistentSegmentTest() public void RemoveKeyFromSegmentTest() { //Arrange - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var keys = new List { "1234" }; var segmentName = "test"; @@ -89,8 +92,8 @@ public void RemoveKeyFromSegmentTest() public void SetAndGetChangeNumberTest() { //Arrange - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var segmentName = "test"; //Act @@ -107,7 +110,9 @@ public void NotifyEventsTest() { //Arrange var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + internalEventsTask.Start(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); var keys = new List { "1234" }; var segmentName = "test"; var toNotify = new List { { segmentName } }; @@ -119,6 +124,7 @@ public void NotifyEventsTest() // Act SdkUpdateFlag = false; segmentCache.AddToSegment(segmentName, keys); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(2000)); //Assert Assert.IsTrue(SdkUpdateFlag); @@ -128,6 +134,7 @@ public void NotifyEventsTest() SdkUpdateFlag = false; eMetadata = null; segmentCache.RemoveFromSegment(segmentName, keys); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(2000)); //Assert Assert.IsTrue(SdkUpdateFlag); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index f2bf14dd..b240462a 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -4,10 +4,12 @@ using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; using Splitio.Services.Filters; +using Splitio.Services.Tasks; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; namespace Splitio_Tests.Unit_Tests.Cache @@ -18,6 +20,7 @@ public class SplitCacheAsyncTests private readonly IFlagSetsFilter _flagSetsFilter; private readonly IFeatureFlagCache _cache; private readonly EventsManager _eventsManager; + private readonly IInternalEventsTask _internalEventsTask; private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; public event EventHandler SdkUpdate; @@ -28,7 +31,9 @@ public SplitCacheAsyncTests() _flagSetsFilter = new FlagSetsFilter(new HashSet()); var splits = new ConcurrentDictionary(); _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - _cache = new InMemorySplitCache(splits, _flagSetsFilter, _eventsManager); + _internalEventsTask = new InternalEventsTask(_eventsManager, new Splitio.Services.Shared.Classes.SplitQueue()); + _internalEventsTask.Start(); + _cache = new InMemorySplitCache(splits, _flagSetsFilter, _internalEventsTask); } [TestMethod] @@ -200,6 +205,7 @@ public async Task NotifyUpdateEventTest() SdkUpdateFlag = false; _cache.Update(toAdd, new List(), -1); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); // Act. var result = await _cache.GetSplitNamesAsync(); @@ -217,6 +223,7 @@ public async Task NotifyUpdateEventTest() SdkUpdateFlag = false; eMetadata = null; _cache.Kill(123, "feature-flag-1", "off"); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsTrue(SdkUpdateFlag); Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index d0938016..a07c9370 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -4,10 +4,12 @@ using Splitio.Services.Cache.Classes; using Splitio.Services.Common; using Splitio.Services.Filters; +using Splitio.Services.Tasks; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Threading; namespace Splitio_Tests.Unit_Tests.Cache { @@ -29,8 +31,8 @@ public SplitCacheTests() public void AddAndGetSplitTest() { //Arrange - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask.Object); var splitName = "test1"; //Act @@ -45,8 +47,8 @@ public void AddAndGetSplitTest() public void AddDuplicateSplitTest() { //Arrange - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask.Object); var splitName = "test1"; //Act @@ -66,8 +68,8 @@ public void AddDuplicateSplitTest() public void GetInexistentSplitTest() { //Arrange - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask.Object); var splitName = "test1"; //Act @@ -84,8 +86,8 @@ public void RemoveSplitTest() var splitName = "test1"; var splits = new ConcurrentDictionary(); splits.TryAdd(splitName, new ParsedSplit() { name = splitName }); - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(splits, _flagSetsFilter.Object, internalEventsTask.Object); //Act splitCache.Update(new List(), new List { splitName }, -1); @@ -99,8 +101,8 @@ public void RemoveSplitTest() public void SetAndGetChangeNumberTest() { //Arrange - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask.Object); var changeNumber = 1234; //Act @@ -115,8 +117,8 @@ public void SetAndGetChangeNumberTest() public void GetAllSplitsTest() { //Arrange - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask.Object); var splitName = "test1"; var splitName2 = "test2"; @@ -135,8 +137,8 @@ public void GetAllSplitsTest() public void AddOrUpdate_WhenUpdateTraffictType_ReturnsTrue() { // Arrange - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask.Object); var splitName = "split_1"; var splitName2 = "split_2"; @@ -178,8 +180,8 @@ public void GetNamesByFlagSetsWithoutFilter() Sets = new HashSet { "set1", "set2" } }); - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet()), internalEventsTask.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -222,8 +224,8 @@ public void GetNamesByFlagSetsWithFilters() defaultTreatment = "on", Sets = new HashSet { "set1", "set2" } }); - Mock> eventsManager = new Mock>(); - var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var splitCache = new InMemorySplitCache(featureFlags, new FlagSetsFilter(new HashSet() { "set1", "set2" }), internalEventsTask.Object); var flagSetNames = new List { "set1", "set2", "set3", "set4" }; // Act. @@ -246,7 +248,9 @@ public void NotifyUpdateEventTest() { // Arrange. var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new Splitio.Services.Shared.Classes.SplitQueue()); + internalEventsTask.Start(); + var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), _flagSetsFilter.Object, internalEventsTask); var splitName = "test1"; var toNotify = new List { { splitName } }; @@ -258,6 +262,7 @@ public void NotifyUpdateEventTest() // Act. SdkUpdateFlag = false; splitCache.Update(new List { new ParsedSplit() { name = splitName } }, new List(), -1); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); // Assert. Assert.IsTrue(SdkUpdateFlag); @@ -269,6 +274,7 @@ public void NotifyUpdateEventTest() SdkUpdateFlag = false; eMetadata = null; splitCache.Kill(123, splitName, "off"); + SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); // Assert. Assert.IsTrue(SdkUpdateFlag); diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index d6d90ff2..9bb6a341 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -1,8 +1,12 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using BitFaster.Caching; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Client.Classes; using Splitio.Services.Common; +using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; using System; +using System.Threading; namespace Splitio_Tests.Unit_Tests.Client { @@ -17,7 +21,9 @@ public class InMemoryReadinessGatesCacheUnitTests public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() { //Arrange - var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); //Act var result = gates.IsReady(); @@ -31,12 +37,15 @@ public void TestFireReadyEvent() { //Arrange EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var gates = new InMemoryReadinessGatesCache(eventsManager); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); + internalEventsTask.Start(); SdkReady += sdkReady_callback; eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); //Act gates.SetReady(); + SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(1000)); // Assert. Assert.IsTrue(SdkReadyFlag); diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index f12c5abc..fecac287 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -1,7 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Common; -using System.Collections.Generic; +using System; +using System.Threading; namespace Splitio_Tests.Unit_Tests.Common { @@ -18,6 +19,7 @@ public void TestFiringEvents() EventDelivery eventDelivery = new EventDelivery(); eventDelivery.Deliver(SdkEvent.SdkReady, null, sdkReady_callback); + SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(1000)); Assert.IsTrue(SdkReady); } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 28f41e65..6495f528 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -48,21 +48,21 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsFalse(SdkTimedOutFlag); // not fired as it is not registered yet eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsTrue(SdkTimedOutFlag); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); - System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(1000)); + System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag2, TimeSpan.FromMilliseconds(1000)); Assert.IsTrue(SdkReadyFlag); Assert.IsTrue(SdkReadyFlag2); Assert.IsFalse(SdkUpdateFlag); @@ -71,14 +71,13 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); Assert.IsFalse(SdkTimedOutFlag); // not fired as suppressed by sdkReady ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); - System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); @@ -87,7 +86,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); - System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); @@ -95,7 +94,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); - System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); @@ -103,7 +102,7 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); - System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); @@ -114,7 +113,6 @@ public void TestFiringEvents() eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); - System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(500)); Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); @@ -136,7 +134,8 @@ public void TestFireOrderEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(500)); + System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(2000)); + System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(2000)); Assert.IsTrue(SdkReadyFlag); Assert.IsTrue(SdkTimedOutFlag); Assert.AreEqual("SdkTimeout", FireFirst); diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index 46424da1..0aa170f7 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -5,6 +5,7 @@ using Splitio.Services.Common; using Splitio.Services.Impressions.Classes; using Splitio.Services.Impressions.Interfaces; +using Splitio.Services.Shared.Classes; using Splitio.Services.Tasks; using Splitio_Tests.Resources; using System; @@ -29,7 +30,9 @@ public void Start_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -53,7 +56,9 @@ public void Start_ShouldNotSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new Mock>().Object); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -72,7 +77,9 @@ public async Task Stop_ShouldSendImpressionsCount() { // Arrange. var config = new ComponentConfig(5, 5); - var statusManager = new InMemoryReadinessGatesCache(new Mock>().Object); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -96,7 +103,9 @@ public async Task Stop_ShouldSendImpressionsCount() public async Task ShouldSend2BulksOfImpressions() { var config = new ComponentConfig(6, 3); - var statusManager = new InMemoryReadinessGatesCache(new Mock>().Object); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs index f3a0ff0e..dc3770ee 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherAsyncTests.cs @@ -2,8 +2,8 @@ using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; -using Splitio.Services.Common; using Splitio.Services.Parsing; +using Splitio.Services.Tasks; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading.Tasks; @@ -24,8 +24,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -48,8 +48,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -66,8 +66,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -84,8 +84,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -107,8 +107,8 @@ public async Task MatchAsyncShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -131,8 +131,8 @@ public async Task MatchAsyncShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -149,8 +149,8 @@ public async Task MatchAsyncShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -167,8 +167,8 @@ public async Task MatchAsyncShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs index f7c1245c..07955ff8 100644 --- a/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs +++ b/tests/Splitio-tests/Unit Tests/Matchers/UserDefinedSegmentMatcherTests.cs @@ -2,8 +2,8 @@ using Moq; using Splitio.Domain; using Splitio.Services.Cache.Classes; -using Splitio.Services.Common; using Splitio.Services.Parsing; +using Splitio.Services.Tasks; using System.Collections.Concurrent; using System.Collections.Generic; @@ -23,8 +23,8 @@ public void MatchShouldReturnTrueOnMatchingSegmentWithKey() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -47,8 +47,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegmentWithKey() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -65,8 +65,8 @@ public void MatchShouldReturnFalseIfSegmentEmptyWithKey() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -83,8 +83,8 @@ public void MatchShouldReturnFalseIfCacheEmptyWithKey() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -106,8 +106,8 @@ public void MatchShouldReturnTrueOnMatchingSegment() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -130,8 +130,8 @@ public void MatchShouldReturnFalseOnNonMatchingSegment() }; var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, keys); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -148,8 +148,8 @@ public void MatchShouldReturnFalseIfSegmentEmpty() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); segmentCache.AddToSegment(segmentName, null); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); @@ -166,8 +166,8 @@ public void MatchShouldReturnFalseIfCacheEmpty() { //Arrange var segmentName = "test-segment"; - Mock> eventsManager = new Mock>(); - var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), eventsManager.Object); + Mock internalEventsTask = new Mock(); + var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask.Object); var matcher = new UserDefinedSegmentMatcher(segmentName, segmentCache); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index c1b9ce49..3b317a03 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -10,7 +10,6 @@ using Splitio.Services.Shared.Classes; using Splitio.Services.SplitFetcher.Interfaces; using Splitio.Services.Tasks; -using Splitio.Telemetry.Domain; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; @@ -28,12 +27,14 @@ public void InitializeSegmentNotExistent() { // Arrange Mock> eventsManager = new Mock>(); - var gates = new InMemoryReadinessGatesCache(eventsManager.Object); + var internalEventsTask = new InternalEventsTask(eventsManager.Object, new SplitQueue()); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); gates.SetReady(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - var cache = new InMemorySegmentCache(segments, eventsManager.Object); + var cache = new InMemorySegmentCache(segments, internalEventsTask); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); var worker = new SegmentTaskWorker(5, segmentsQueue); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs index 83074558..c192b4ed 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentUnitTests.cs @@ -3,9 +3,9 @@ using Splitio.Domain; using Splitio.Services.Cache.Classes; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; using Splitio.Services.SegmentFetcher.Classes; using Splitio.Services.SplitFetcher.Interfaces; +using Splitio.Services.Tasks; using System; using System.Collections.Concurrent; using System.Threading.Tasks; @@ -23,8 +23,8 @@ public async Task FetchSegmentNullChangesFetcherResponseShouldNotUpdateCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - Mock> eventsManager = new Mock>(); - var cache = new InMemorySegmentCache(segments, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var cache = new InMemorySegmentCache(segments, internalEventsTask.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient @@ -46,8 +46,8 @@ public async Task FetchSegmentShouldUpdateSegmentsCache() var statusManager = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); - Mock> eventsManager = new Mock>(); - var cache = new InMemorySegmentCache(segments, eventsManager.Object); + Mock internalEventsTask = new Mock(); + var cache = new InMemorySegmentCache(segments, internalEventsTask.Object); var segmentFetcher = new SelfRefreshingSegment("payed", apiFetcher, cache, statusManager.Object); apiClient diff --git a/tests/Splitio-tests/Unit Tests/Tasks/InternalEvenstTaskTests.cs b/tests/Splitio-tests/Unit Tests/Tasks/InternalEvenstTaskTests.cs new file mode 100644 index 00000000..a706c5af --- /dev/null +++ b/tests/Splitio-tests/Unit Tests/Tasks/InternalEvenstTaskTests.cs @@ -0,0 +1,39 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Splitio.Domain; +using Splitio.Services.Common; +using Splitio.Services.EventSource.Workers; +using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Splitio_Tests.Unit_Tests.Tasks +{ + [TestClass] + public class InternalEvenstTaskTests + { + + [TestMethod] + public async Task TestFiringEvents() + { + //Act + SplitQueue internalEventsQueue = new SplitQueue(); + Mock> eventManager = new Mock>(); + InternalEventsTask internalEventsTask = new InternalEventsTask(eventManager.Object, internalEventsQueue); + internalEventsTask.Start(); + + await internalEventsQueue.EnqueueAsync(new SdkEventNotification(SdkInternalEvent.SdkReady, null)); + System.Threading.SpinWait.SpinUntil(() => eventManager.Invocations.Count>0, TimeSpan.FromMilliseconds(2000)); + eventManager.Verify(mock => mock.NotifyInternalEvent(SdkInternalEvent.SdkReady, null), Times.Exactly(1)); + + var metadata = new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } }); + await internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, metadata); + System.Threading.SpinWait.SpinUntil(() => eventManager.Invocations.Count > 1, TimeSpan.FromMilliseconds(2000)); + eventManager.Verify(mock => mock.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, metadata), Times.Exactly(1)); + + internalEventsTask.Stop(); + } + } +} diff --git a/tests/Splitio.Integration-tests/EventSourceClientTests.cs b/tests/Splitio.Integration-tests/EventSourceClientTests.cs index b7850c78..65f57d56 100644 --- a/tests/Splitio.Integration-tests/EventSourceClientTests.cs +++ b/tests/Splitio.Integration-tests/EventSourceClientTests.cs @@ -370,7 +370,9 @@ private static (IEventSourceClient, BlockingCollection, var sseHttpClient = new SplitioHttpClient("api-key", config, new Dictionary()); var telemetryRuntimeProducer = new InMemoryTelemetryStorage(); var notificationManagerKeeper = new NotificationManagerKeeper(telemetryRuntimeProducer, streamingStatusQueue); - var statusManager = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); + EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); + var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var tasksManager = new TasksManager(statusManager); var task = tasksManager.NewOnTimeTask(Enums.Task.SSEConnect); From ef78c1892b690ffc5aea2ec8f74f706bceb10451 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 26 Jan 2026 09:54:10 -0800 Subject: [PATCH 70/87] added exception handling for add to queue task --- .../Cache/Classes/InMemoryReadinessGatesCache.cs | 11 ++++++++++- .../Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 10 +++++++++- .../Services/Cache/Classes/InMemorySegmentCache.cs | 9 +++++++-- .../Services/Cache/Classes/InMemorySplitCache.cs | 9 +++++++-- .../Unit Tests/Common/EventDeliveryTests.cs | 13 ++++++++++--- 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index 6252411c..06cf20a5 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -1,7 +1,10 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; using Splitio.Services.Tasks; using System.Threading; +using System.Threading.Tasks; namespace Splitio.Services.Client.Classes { @@ -10,6 +13,7 @@ public class InMemoryReadinessGatesCache : IStatusManager private readonly CountdownEvent _sdkReady = new CountdownEvent(1); private readonly CountdownEvent _sdkDestroyed = new CountdownEvent(1); private readonly IInternalEventsTask _internalEventsTask; + private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemoryReadinessGatesCache)); public InMemoryReadinessGatesCache(IInternalEventsTask internalEventsTask) { @@ -29,7 +33,7 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); - _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null); + _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); } public void SetDestroy() @@ -41,5 +45,10 @@ public bool IsDestroyed() { return _sdkDestroyed.IsSet; } + + public void OnAddToQueueFailed(Task task) + { + _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); + } } } diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 28b47ff2..749b43d0 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -1,5 +1,7 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Logger; +using Splitio.Services.Shared.Classes; using Splitio.Services.Tasks; using System.Collections.Concurrent; using System.Collections.Generic; @@ -12,6 +14,7 @@ public class InMemoryRuleBasedSegmentCache : IRuleBasedSegmentCache private readonly ConcurrentDictionary _cache; private long _changeNumber; private readonly IInternalEventsTask _internalEventsTask; + private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemoryRuleBasedSegmentCache)); public InMemoryRuleBasedSegmentCache(ConcurrentDictionary cache, IInternalEventsTask internalEventsTask, @@ -61,7 +64,7 @@ public void Update(List toAdd, List toRemove, long til SetChangeNumber(till); _internalEventsTask.AddToQueue(SdkInternalEvent.RuleBasedSegmentsUpdated, - new EventMetadata(SdkEventType.SegmentsUpdate, new List())); + new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); } public void SetChangeNumber(long changeNumber) @@ -81,5 +84,10 @@ public Task GetAsync(string name) return Task.FromResult(Get(name)); } #endregion + + public void OnAddToQueueFailed(Task task) + { + _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); + } } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 3dd3195a..27d1ac55 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -35,7 +35,7 @@ public void AddToSegment(string segmentName, List segmentKeys) segment.AddKeys(segmentKeys); _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(SdkEventType.SegmentsUpdate, new List())); + new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); } public void RemoveFromSegment(string segmentName, List segmentKeys) @@ -44,7 +44,7 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) { segment.RemoveKeys(segmentKeys); _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, - new EventMetadata(SdkEventType.SegmentsUpdate, new List())); + new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); } } @@ -115,5 +115,10 @@ public Task IsInSegmentAsync(string segmentName, string key) return Task.FromResult(IsInSegment(segmentName, key)); } #endregion + + public void OnAddToQueueFailed(Task task) + { + _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); + } } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index 29530591..cc508c87 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -79,7 +79,7 @@ public void Update(List toAdd, List toRemove, long till) SetChangeNumber(till); _internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, - new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)); + new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); } public void SetChangeNumber(long changeNumber) @@ -152,7 +152,7 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); _internalEventsTask.AddToQueue(SdkInternalEvent.FlagKilledNotification, - new EventMetadata(SdkEventType.FlagsUpdate, new List { { featureFlag.name } })); + new EventMetadata(SdkEventType.FlagsUpdate, new List { { featureFlag.name } })).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); } @@ -275,5 +275,10 @@ private void RemoveNames(string key, string name) if (names.Count == 0) _flagSets.TryRemove(key, out HashSet _); } #endregion + + public void OnAddToQueueFailed(Task task) + { + _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs index fecac287..1b09e7b8 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventDeliveryTests.cs @@ -18,16 +18,23 @@ public void TestFiringEvents() //Act EventDelivery eventDelivery = new EventDelivery(); - eventDelivery.Deliver(SdkEvent.SdkReady, null, sdkReady_callback); + eventDelivery.Deliver(SdkEvent.SdkReady, null, SdkReadyCallback); SpinWait.SpinUntil(() => SdkReady, TimeSpan.FromMilliseconds(1000)); - Assert.IsTrue(SdkReady); + + eventDelivery.Deliver(SdkEvent.SdkReady, null, SdkReadyCallbackWithException); + // should not cause exception here } - private void sdkReady_callback(EventMetadata metadata) + private void SdkReadyCallback(EventMetadata metadata) { SdkReady = true; eMetadata = metadata; } + + private void SdkReadyCallbackWithException(EventMetadata metadata) + { + throw new Exception("something wrong"); + } } } From b30127ad0ad4a2cc9044a97b3c4d38b8028fdc66 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 26 Jan 2026 10:11:51 -0800 Subject: [PATCH 71/87] updated sdk block until ready service --- .../Client/Classes/SelfRefreshingClient.cs | 2 +- .../SelfRefreshingBlockUntilReadyService.cs | 17 +++++++++++------ ...SelfRefreshingBlockUntilReadyServiceTests.cs | 8 +++++++- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 54dfc606..4742a96c 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -210,7 +210,7 @@ private void BuildManager() private void BuildBlockUntilReadyService() { - _blockUntilReadyService = new SelfRefreshingBlockUntilReadyService(_statusManager, _telemetryInitProducer, _eventsManager); + _blockUntilReadyService = new SelfRefreshingBlockUntilReadyService(_statusManager, _telemetryInitProducer, _internalEventsTask); } private void BuildTelemetrySyncTask() diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index b62c505f..dc5a23af 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -1,11 +1,11 @@ using Splitio.Domain; using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; using Splitio.Services.Logger; using Splitio.Services.Shared.Interfaces; +using Splitio.Services.Tasks; using Splitio.Telemetry.Storages; using System; -using System.Collections.Generic; +using System.Threading.Tasks; namespace Splitio.Services.Shared.Classes { @@ -14,15 +14,15 @@ public class SelfRefreshingBlockUntilReadyService : IBlockUntilReadyService private static readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(SelfRefreshingBlockUntilReadyService)); private readonly IStatusManager _statusManager; + private readonly IInternalEventsTask _internalEventsTask; private readonly ITelemetryInitProducer _telemetryInitProducer; - private readonly IEventsManager _eventsManager; public SelfRefreshingBlockUntilReadyService(IStatusManager statusManager, ITelemetryInitProducer telemetryInitProducer, - IEventsManager eventsManager) + IInternalEventsTask internalEventsTask) { _statusManager = statusManager; _telemetryInitProducer = telemetryInitProducer; - _eventsManager = eventsManager; + _internalEventsTask = internalEventsTask; } public void BlockUntilReady(int blockMilisecondsUntilReady) @@ -36,7 +36,7 @@ public void BlockUntilReady(int blockMilisecondsUntilReady) if (!_statusManager.WaitUntilReady(blockMilisecondsUntilReady)) { - _eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); + _internalEventsTask.AddToQueue(SdkInternalEvent.SdkTimedOut, null).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); _telemetryInitProducer.RecordBURTimeout(); throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady} milliseconds"); } @@ -54,5 +54,10 @@ public bool IsSdkReady() return false; } } + + public void OnAddToQueueFailed(Task task) + { + _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); + } } } diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index ef00e607..35e4581a 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -4,8 +4,10 @@ using Splitio.Services.Cache.Interfaces; using Splitio.Services.Common; using Splitio.Services.Shared.Classes; +using Splitio.Services.Tasks; using Splitio.Telemetry.Storages; using System; +using System.Threading; namespace Splitio_Tests.Unit_Tests.Shared { @@ -23,7 +25,10 @@ public void TestFireTimedOutEvent() Mock statusManager = new Mock(); Mock telemetryProducer = new Mock(); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, eventsManager); + IInternalEventsTask internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, internalEventsTask); + internalEventsTask.Start(); + SdkTimedOut += sdkTimeout_callback; eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimedOut); statusManager @@ -38,6 +43,7 @@ public void TestFireTimedOutEvent() catch { } // Assert. + SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(1000)); Assert.IsTrue(SdkTimedOutFlag); Assert.AreEqual(null, eMetadata); } From bb1473c7b4e8781ac9bc00df7b9df2962072197d Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 26 Jan 2026 10:38:30 -0800 Subject: [PATCH 72/87] added try catch when running the event callback --- src/Splitio/Services/Common/EventDelivery.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 1ba68871..676fc155 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -13,7 +13,7 @@ public void Deliver(E sdkEvent, M eventMetadata, Action callbackAction) { try { - Thread eventCallbackThread = new Thread(() => callbackAction(eventMetadata)); + Thread eventCallbackThread = new Thread(() => RunCallbackAction(callbackAction, eventMetadata)); eventCallbackThread.Start(); } catch (Exception ex) @@ -23,5 +23,19 @@ public void Deliver(E sdkEvent, M eventMetadata, Action callbackAction) _logger.Debug($"EventDelivery worker Execute exception", ex); } } + + private void RunCallbackAction(Action callbackAction, M eventMetadata) + { + try + { + callbackAction(eventMetadata); + } + catch (Exception ex) + { + if (ex is OperationCanceledException) return; + + _logger.Debug($"Exception in callback", ex); + } + } } } From bc10a937e61a59eb21320a8c1a985b0384d37cb5 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 26 Jan 2026 11:01:15 -0800 Subject: [PATCH 73/87] polish --- src/Splitio/Domain/EventMetadata.cs | 6 ++---- src/Splitio/Services/Common/EventDelivery.cs | 4 ++-- src/Splitio/Services/Tasks/InternalEventsTask.cs | 2 +- .../Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs | 2 +- .../Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs | 2 +- .../Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs | 2 +- tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs | 2 +- .../Shared/SelfRefreshingBlockUntilReadyServiceTests.cs | 2 +- 8 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/Splitio/Domain/EventMetadata.cs b/src/Splitio/Domain/EventMetadata.cs index 2070bb14..6b5c4302 100644 --- a/src/Splitio/Domain/EventMetadata.cs +++ b/src/Splitio/Domain/EventMetadata.cs @@ -1,13 +1,11 @@ using System.Collections.Generic; -using Splitio.Services.InputValidation.Classes; -using System.Linq; namespace Splitio.Domain { public class EventMetadata { - private List _names; - private SdkEventType _type; + private readonly List _names; + private readonly SdkEventType _type; public EventMetadata(SdkEventType type, List names) { diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 676fc155..352ae763 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -9,11 +9,11 @@ public class EventDelivery : IEventDelivery { private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("EventDelivery"); - public void Deliver(E sdkEvent, M eventMetadata, Action callbackAction) + public void Deliver(E sdkEvent, M eventMetadata, Action handler) { try { - Thread eventCallbackThread = new Thread(() => RunCallbackAction(callbackAction, eventMetadata)); + Thread eventCallbackThread = new Thread(() => RunCallbackAction(handler, eventMetadata)); eventCallbackThread.Start(); } catch (Exception ex) diff --git a/src/Splitio/Services/Tasks/InternalEventsTask.cs b/src/Splitio/Services/Tasks/InternalEventsTask.cs index 5e654dbf..f0534dbe 100644 --- a/src/Splitio/Services/Tasks/InternalEventsTask.cs +++ b/src/Splitio/Services/Tasks/InternalEventsTask.cs @@ -10,7 +10,7 @@ namespace Splitio.Services.Tasks { public class InternalEventsTask : BaseWorker, IQueueObserver, IInternalEventsTask { - IEventsManager _eventsManager; + private readonly IEventsManager _eventsManager; private readonly ISplitLogger _logger = WrapperAdapter.Instance().GetLogger("InternalEventsTask"); private readonly SplitQueue _queue; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index 159d4eb8..eb6739bf 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -19,7 +19,7 @@ public class RuleBasedSegmentCacheTests private EventsManager _eventsManager; private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - private IInternalEventsTask _internalEventsTask; + private InternalEventsTask _internalEventsTask; public event EventHandler SdkUpdate; public event EventHandler SdkReady; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index f6e36fed..60bae8f3 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -20,7 +20,7 @@ public class SegmentCacheAsyncTests private EventsManager _eventsManager; private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; - private IInternalEventsTask _internalEventsTask; + private InternalEventsTask _internalEventsTask; public event EventHandler SdkUpdate; public event EventHandler SdkReady; diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs index b240462a..a30114b2 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheAsyncTests.cs @@ -20,7 +20,7 @@ public class SplitCacheAsyncTests private readonly IFlagSetsFilter _flagSetsFilter; private readonly IFeatureFlagCache _cache; private readonly EventsManager _eventsManager; - private readonly IInternalEventsTask _internalEventsTask; + private readonly InternalEventsTask _internalEventsTask; private bool SdkUpdateFlag = false; private EventMetadata eMetadata = null; public event EventHandler SdkUpdate; diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 6495f528..7b34c035 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -149,7 +149,7 @@ void ResetAllVariables() SdkUpdateFlag = false; } - void VerifyMetadata(EventMetadata eMetdata) + static void VerifyMetadata(EventMetadata eMetdata) { Assert.IsTrue(eMetdata.GetNames().Count == 1); Assert.IsTrue(eMetdata.GetNames().Contains("flag1")); diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs index 35e4581a..379d0ace 100644 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs @@ -25,7 +25,7 @@ public void TestFireTimedOutEvent() Mock statusManager = new Mock(); Mock telemetryProducer = new Mock(); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - IInternalEventsTask internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); + InternalEventsTask internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, internalEventsTask); internalEventsTask.Start(); From 8ff55a7ba8ba509ed307ffdbc66df811beae8afe Mon Sep 17 00:00:00 2001 From: Bill Al Date: Mon, 26 Jan 2026 11:16:42 -0800 Subject: [PATCH 74/87] added threadpool for event handler call --- src/Splitio/Services/Common/EventDelivery.cs | 13 +++++++++---- .../Splitio.Integration-tests/PollingClientTests.cs | 1 + 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Splitio/Services/Common/EventDelivery.cs b/src/Splitio/Services/Common/EventDelivery.cs index 352ae763..c2dfbef4 100644 --- a/src/Splitio/Services/Common/EventDelivery.cs +++ b/src/Splitio/Services/Common/EventDelivery.cs @@ -13,8 +13,8 @@ public void Deliver(E sdkEvent, M eventMetadata, Action handler) { try { - Thread eventCallbackThread = new Thread(() => RunCallbackAction(handler, eventMetadata)); - eventCallbackThread.Start(); + object[] parameters = new object[] { handler, eventMetadata }; + ThreadPool.QueueUserWorkItem(RunCallbackAction, parameters); } catch (Exception ex) { @@ -24,11 +24,16 @@ public void Deliver(E sdkEvent, M eventMetadata, Action handler) } } - private void RunCallbackAction(Action callbackAction, M eventMetadata) + private void RunCallbackAction(object state) { try { - callbackAction(eventMetadata); + if (state is object[] parameters) + { + Action callbackAction = (Action)parameters[0]; + M eventMetadata = (M)parameters[1]; + callbackAction(eventMetadata); + } } catch (Exception ex) { diff --git a/tests/Splitio.Integration-tests/PollingClientTests.cs b/tests/Splitio.Integration-tests/PollingClientTests.cs index 8b01959c..ee7dde3b 100644 --- a/tests/Splitio.Integration-tests/PollingClientTests.cs +++ b/tests/Splitio.Integration-tests/PollingClientTests.cs @@ -180,6 +180,7 @@ public void GetTreatment_WithtBUR_ReturnsTimeOutException() } // Assert. + SpinWait.SpinUntil(() => SdkTimeout, TimeSpan.FromMilliseconds(1000)); Assert.IsTrue(SdkTimeout); Assert.IsFalse(isSdkReady); Assert.AreEqual("SDK was not ready in 0 milliseconds", exceptionMessage); From f1d8a3bd620dda09de974e05d491db16f7b320f8 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 29 Jan 2026 08:09:04 -0800 Subject: [PATCH 75/87] use Task to add to queue and removed timeout event --- src/Splitio/Domain/EventsManagerConfig.cs | 16 +---- src/Splitio/Domain/SdkEvent.cs | 1 - src/Splitio/Domain/SdkInternalEvent.cs | 1 - .../Classes/InMemoryReadinessGatesCache.cs | 6 +- .../Classes/InMemoryRuleBasedSegmentCache.cs | 6 +- .../Cache/Classes/InMemorySegmentCache.cs | 12 +++- .../Cache/Classes/InMemorySplitCache.cs | 13 +++- .../Services/Client/Classes/SplitClient.cs | 8 --- .../Client/Interfaces/ISplitClient.cs | 1 - .../SelfRefreshingBlockUntilReadyService.cs | 1 - .../Common/EventsManagerConfigTests.cs | 16 +---- .../Unit Tests/Common/EventsManagerTests.cs | 61 +++--------------- ...lfRefreshingBlockUntilReadyServiceTests.cs | 62 ------------------- .../PollingClientTests.cs | 9 --- 14 files changed, 44 insertions(+), 169 deletions(-) delete mode 100644 tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs diff --git a/src/Splitio/Domain/EventsManagerConfig.cs b/src/Splitio/Domain/EventsManagerConfig.cs index 8783b9ff..06d51da7 100644 --- a/src/Splitio/Domain/EventsManagerConfig.cs +++ b/src/Splitio/Domain/EventsManagerConfig.cs @@ -36,31 +36,19 @@ public EventsManagerConfig() SdkInternalEvent.FlagKilledNotification, SdkInternalEvent.SegmentsUpdated } - }, - { SdkEvent.SdkReadyTimeout, new HashSet - { - SdkInternalEvent.SdkTimedOut - } } }; - SuppressedBy = new Dictionary> - { - { SdkEvent.SdkReadyTimeout, new HashSet - { SdkEvent.SdkReady } - - } - }; + SuppressedBy = new Dictionary>(); ExecutionLimits = new Dictionary { - { SdkEvent.SdkReadyTimeout, -1 }, { SdkEvent.SdkReady, 1 }, { SdkEvent.SdkUpdate, -1 } }; HashSet sortedEvents = new HashSet(); - foreach (SdkEvent sdkEvent in new List { SdkEvent.SdkReady, SdkEvent.SdkReadyTimeout, SdkEvent.SdkUpdate }) + foreach (SdkEvent sdkEvent in new List { SdkEvent.SdkReady, SdkEvent.SdkUpdate }) { sortedEvents = DFSRecursive(sdkEvent, sortedEvents); } diff --git a/src/Splitio/Domain/SdkEvent.cs b/src/Splitio/Domain/SdkEvent.cs index 5c8fbe70..f069df00 100644 --- a/src/Splitio/Domain/SdkEvent.cs +++ b/src/Splitio/Domain/SdkEvent.cs @@ -4,7 +4,6 @@ namespace Splitio.Domain public enum SdkEvent { SdkUpdate, - SdkReadyTimeout, SdkReady } } diff --git a/src/Splitio/Domain/SdkInternalEvent.cs b/src/Splitio/Domain/SdkInternalEvent.cs index 651d0cf2..64e3b0eb 100644 --- a/src/Splitio/Domain/SdkInternalEvent.cs +++ b/src/Splitio/Domain/SdkInternalEvent.cs @@ -8,7 +8,6 @@ public enum SdkInternalEvent RuleBasedSegmentsUpdated, SegmentsUpdated, LargeSegmentsUpdated, - SdkTimedOut, SdkReady } } diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index 06cf20a5..637d69df 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -33,7 +33,11 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); - _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); } public void SetDestroy() diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 749b43d0..14de743a 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -63,8 +63,12 @@ public void Update(List toAdd, List toRemove, long til } SetChangeNumber(till); - _internalEventsTask.AddToQueue(SdkInternalEvent.RuleBasedSegmentsUpdated, + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); } public void SetChangeNumber(long changeNumber) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs index 27d1ac55..243d9c6e 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySegmentCache.cs @@ -34,8 +34,12 @@ public void AddToSegment(string segmentName, List segmentKeys) } segment.AddKeys(segmentKeys); - _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); } public void RemoveFromSegment(string segmentName, List segmentKeys) @@ -43,8 +47,12 @@ public void RemoveFromSegment(string segmentName, List segmentKeys) if (_segments.TryGetValue(segmentName, out Segment segment)) { segment.RemoveKeys(segmentKeys); - _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); } } diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index cc508c87..b88ba7e4 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -78,8 +78,12 @@ public void Update(List toAdd, List toRemove, long till) } SetChangeNumber(till); - _internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); } public void SetChangeNumber(long changeNumber) @@ -151,9 +155,12 @@ public void Kill(long changeNumber, string splitName, string defaultTreatment) featureFlag.changeNumber = changeNumber; _featureFlags.AddOrUpdate(featureFlag.name, featureFlag, (key, oldValue) => featureFlag); - _internalEventsTask.AddToQueue(SdkInternalEvent.FlagKilledNotification, + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.FlagKilledNotification, new EventMetadata(SdkEventType.FlagsUpdate, new List { { featureFlag.name } })).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); - + }); + task.Start(); } public List GetSplitNames() diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 267a9c02..ef5867ab 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -84,7 +84,6 @@ public event EventHandler SdkReady } } public event EventHandler SdkUpdate; - public event EventHandler SdkTimedOut; protected SplitClient(string apikey) { @@ -519,13 +518,11 @@ private void RegisterEvents() { _eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); _eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); - _eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); } private void UnregisterEvents() { _eventsManager.Unregister(SdkEvent.SdkReady); _eventsManager.Unregister(SdkEvent.SdkUpdate); - _eventsManager.Unregister(SdkEvent.SdkReadyTimeout); } private List GetTreatmentsSync(Enums.API method, Key key, List features, Dictionary attributes = null, EvaluationOptions evaluationOptions = null) { @@ -624,11 +621,6 @@ private void TriggerSdkUpdate(EventMetadata metaData) { SdkUpdate?.Invoke(this, metaData); } - - private void TriggerSdkTimeout(EventMetadata metaData) - { - SdkTimedOut?.Invoke(this, metaData); - } #endregion } } \ No newline at end of file diff --git a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs index a18982dd..78502783 100644 --- a/src/Splitio/Services/Client/Interfaces/ISplitClient.cs +++ b/src/Splitio/Services/Client/Interfaces/ISplitClient.cs @@ -8,7 +8,6 @@ public interface ISplitClient : ISplitClientAsync { event EventHandler SdkReady; event EventHandler SdkUpdate; - event EventHandler SdkTimedOut; /// /// Returns the treatment to show this key for this feature flag. diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index dc5a23af..542c8f28 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -36,7 +36,6 @@ public void BlockUntilReady(int blockMilisecondsUntilReady) if (!_statusManager.WaitUntilReady(blockMilisecondsUntilReady)) { - _internalEventsTask.AddToQueue(SdkInternalEvent.SdkTimedOut, null).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); _telemetryInitProducer.RecordBURTimeout(); throw new TimeoutException($"SDK was not ready in {blockMilisecondsUntilReady} milliseconds"); } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs index d8de94f3..3dec9f26 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerConfigTests.cs @@ -21,16 +21,11 @@ public void BuildInstance() config.Prerequisites.TryGetValue(SdkEvent.SdkUpdate, out var ready2); Assert.IsTrue(ready2.Contains(SdkEvent.SdkReady)); - config.ExecutionLimits.TryGetValue(SdkEvent.SdkReadyTimeout, out var timout); - Assert.AreEqual(-1, timout); config.ExecutionLimits.TryGetValue(SdkEvent.SdkUpdate, out var update); Assert.AreEqual(-1, update); config.ExecutionLimits.TryGetValue(SdkEvent.SdkReady, out var ready); Assert.AreEqual(1, ready); - config.RequireAny.TryGetValue(SdkEvent.SdkReadyTimeout, out var require3); - Assert.AreEqual(1, require3.Count); - Assert.IsTrue(require3.Contains(SdkInternalEvent.SdkTimedOut)); config.RequireAny.TryGetValue(SdkEvent.SdkUpdate, out var require2); Assert.AreEqual(4, require2.Count); Assert.IsTrue(require2.Contains(SdkInternalEvent.SegmentsUpdated)); @@ -38,24 +33,17 @@ public void BuildInstance() Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagKilledNotification)); Assert.IsTrue(require2.Contains(SdkInternalEvent.FlagsUpdated)); - config.SuppressedBy.TryGetValue(SdkEvent.SdkReadyTimeout, out var require4); - Assert.AreEqual(1, require3.Count); - Assert.IsTrue(require4.Contains(SdkEvent.SdkReady)); - int order = 0; - Assert.AreEqual(3, config.EvaluationOrder.Count); + Assert.AreEqual(2, config.EvaluationOrder.Count); foreach (var sdkEvent in config.EvaluationOrder) { order++; switch (order) { case 1: - Assert.AreEqual(SdkEvent.SdkReadyTimeout, sdkEvent); - break; - case 2: Assert.AreEqual(SdkEvent.SdkReady, sdkEvent); break; - case 3: + case 2: Assert.AreEqual(SdkEvent.SdkUpdate, sdkEvent); break; } diff --git a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs index 7b34c035..e4f3e25a 100644 --- a/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/EventsManagerTests.cs @@ -11,13 +11,11 @@ public class EventsManagerTests { private bool SdkReadyFlag = false; private bool SdkReadyFlag2 = false; - private bool SdkTimedOutFlag = false; private bool SdkUpdateFlag = false; private string FireFirst = ""; private EventMetadata eMetadata = null; public event EventHandler SdkReady; public event EventHandler SdkUpdate; - public event EventHandler SdkTimedOut; [TestMethod] public void TestFiringEvents() @@ -29,7 +27,6 @@ public void TestFiringEvents() SdkReady += sdkReady_callback; SdkReady += sdkReady_callback2; SdkUpdate += sdkUpdate_callback; - SdkTimedOut += sdkTimedOut_callback; Dictionary metaData = new Dictionary { { "flags", new List {{ "flag1" }} } @@ -44,20 +41,6 @@ public void TestFiringEvents() eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); - Assert.IsFalse(SdkTimedOutFlag); - - ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); - Assert.IsFalse(SdkReadyFlag); - Assert.IsFalse(SdkUpdateFlag); - Assert.IsFalse(SdkTimedOutFlag); // not fired as it is not registered yet - - eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(1000)); - Assert.IsFalse(SdkReadyFlag); - Assert.IsFalse(SdkUpdateFlag); - Assert.IsTrue(SdkTimedOutFlag); ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); @@ -66,19 +49,10 @@ public void TestFiringEvents() Assert.IsTrue(SdkReadyFlag); Assert.IsTrue(SdkReadyFlag2); Assert.IsFalse(SdkUpdateFlag); - Assert.IsFalse(SdkTimedOutFlag); - - ResetAllVariables(); - eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); - Assert.IsFalse(SdkReadyFlag); - Assert.IsFalse(SdkUpdateFlag); - Assert.IsFalse(SdkTimedOutFlag); // not fired as suppressed by sdkReady ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagKilledNotification, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); - Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); @@ -87,7 +61,6 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.SegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); - Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); @@ -95,7 +68,6 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.RuleBasedSegmentsUpdated, new EventMetadata(SdkEventType.SegmentsUpdate, new List())); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); - Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); @@ -103,7 +75,6 @@ public void TestFiringEvents() ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(1000)); - Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsTrue(SdkUpdateFlag); Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); @@ -113,7 +84,6 @@ public void TestFiringEvents() eventsManager.Unregister(SdkEvent.SdkUpdate); // should not cause exception ResetAllVariables(); eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, new EventMetadata(SdkEventType.FlagsUpdate, new List { { "flag1" } })); - Assert.IsFalse(SdkTimedOutFlag); Assert.IsFalse(SdkReadyFlag); Assert.IsFalse(SdkUpdateFlag); } @@ -126,27 +96,28 @@ public void TestFireOrderEvents() EventsManager eventsManager = new EventsManager(config, new EventDelivery()); SdkReady += sdkReady_callback; - SdkTimedOut += sdkTimedOut_callback; + SdkUpdate += sdkUpdate_callback; eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimeout); + eventsManager.Register(SdkEvent.SdkUpdate, TriggerSdkUpdate); ResetAllVariables(); - eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkTimedOut, null); eventsManager.NotifyInternalEvent(SdkInternalEvent.SdkReady, null); - System.Threading.SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(2000)); + eventsManager.NotifyInternalEvent(SdkInternalEvent.FlagsUpdated, null); + System.Threading.SpinWait.SpinUntil(() => SdkUpdateFlag, TimeSpan.FromMilliseconds(2000)); System.Threading.SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(2000)); Assert.IsTrue(SdkReadyFlag); - Assert.IsTrue(SdkTimedOutFlag); - Assert.AreEqual("SdkTimeout", FireFirst); + Assert.IsTrue(SdkUpdateFlag); + Assert.AreEqual("SdkReady", FireFirst); } - void ResetAllVariables() + + void ResetAllVariables() { SdkReadyFlag = false; SdkReadyFlag2 = false; - SdkTimedOutFlag = false; eMetadata = null; SdkUpdateFlag = false; + FireFirst = ""; } static void VerifyMetadata(EventMetadata eMetdata) @@ -159,6 +130,7 @@ private void sdkUpdate_callback(object sender, EventMetadata metadata) { SdkUpdateFlag = true; eMetadata = metadata; + if (FireFirst.Equals("")) FireFirst = "SdkUpdate"; } private void sdkReady_callback(object sender, EventMetadata metadata) @@ -174,13 +146,6 @@ private void sdkReady_callback2(object sender, EventMetadata metadata) eMetadata = metadata; } - private void sdkTimedOut_callback(object sender, EventMetadata metadata) - { - SdkTimedOutFlag = true; - eMetadata = metadata; - if (FireFirst.Equals("")) FireFirst = "SdkTimeout"; - } - private void TriggerSdkReady(EventMetadata metaData) { SdkReady?.Invoke(this, metaData); @@ -190,11 +155,5 @@ private void TriggerSdkUpdate(EventMetadata metaData) { SdkUpdate?.Invoke(this, metaData); } - - private void TriggerSdkTimeout(EventMetadata metaData) - { - SdkTimedOut?.Invoke(this, metaData); - } - } } diff --git a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs b/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs deleted file mode 100644 index 379d0ace..00000000 --- a/tests/Splitio-tests/Unit Tests/Shared/SelfRefreshingBlockUntilReadyServiceTests.cs +++ /dev/null @@ -1,62 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Splitio.Domain; -using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Common; -using Splitio.Services.Shared.Classes; -using Splitio.Services.Tasks; -using Splitio.Telemetry.Storages; -using System; -using System.Threading; - -namespace Splitio_Tests.Unit_Tests.Shared -{ - [TestClass] - public class SelfRefreshingBlockUntilReadyServiceTests - { - private bool SdkTimedOutFlag = false; - private EventMetadata eMetadata = null; - public event EventHandler SdkTimedOut; - - [TestMethod] - public void TestFireTimedOutEvent() - { - //Arrange - Mock statusManager = new Mock(); - Mock telemetryProducer = new Mock(); - EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - InternalEventsTask internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var bur = new SelfRefreshingBlockUntilReadyService(statusManager.Object, telemetryProducer.Object, internalEventsTask); - internalEventsTask.Start(); - - SdkTimedOut += sdkTimeout_callback; - eventsManager.Register(SdkEvent.SdkReadyTimeout, TriggerSdkTimedOut); - statusManager - .Setup(mock => mock.WaitUntilReady(1)) - .Returns(false); - - //Act - try - { - bur.BlockUntilReady(1); - } - catch { } - - // Assert. - SpinWait.SpinUntil(() => SdkTimedOutFlag, TimeSpan.FromMilliseconds(1000)); - Assert.IsTrue(SdkTimedOutFlag); - Assert.AreEqual(null, eMetadata); - } - - private void sdkTimeout_callback(object sender, EventMetadata metadata) - { - SdkTimedOutFlag = true; - eMetadata = metadata; - } - - private void TriggerSdkTimedOut(EventMetadata metaData) - { - SdkTimedOut?.Invoke(this, metaData); - } - } -} diff --git a/tests/Splitio.Integration-tests/PollingClientTests.cs b/tests/Splitio.Integration-tests/PollingClientTests.cs index ee7dde3b..306b7b8d 100644 --- a/tests/Splitio.Integration-tests/PollingClientTests.cs +++ b/tests/Splitio.Integration-tests/PollingClientTests.cs @@ -18,7 +18,6 @@ namespace Splitio.Integration_tests public class PollingClientTests : BaseIntegrationTests { private static readonly HttpClientMock httpClientMock = new HttpClientMock("PollingClientTests"); - private bool SdkTimeout = false; public PollingClientTests() : base("Polling") { } @@ -163,7 +162,6 @@ public void GetTreatment_WithtBUR_ReturnsTimeOutException() var splitFactory = new SplitFactory(apikey, configurations); var client = (SplitClient)splitFactory.Client(); - client.SdkTimedOut += sdkTimeout_callback; // Act. var exceptionMessage = ""; @@ -180,8 +178,6 @@ public void GetTreatment_WithtBUR_ReturnsTimeOutException() } // Assert. - SpinWait.SpinUntil(() => SdkTimeout, TimeSpan.FromMilliseconds(1000)); - Assert.IsTrue(SdkTimeout); Assert.IsFalse(isSdkReady); Assert.AreEqual("SDK was not ready in 0 milliseconds", exceptionMessage); @@ -729,11 +725,6 @@ private static List GetImpressionsCountsSentBackend(HttpClientM return impressions; } - - private void sdkTimeout_callback(object sender, EventMetadata metadata) - { - SdkTimeout = true; - } #endregion } } From b623041dad8e2ff5fca3d548d0e16358c3e482aa Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 29 Jan 2026 11:10:29 -0800 Subject: [PATCH 76/87] polishing --- src/Splitio/Services/Common/ISdkEventTask.cs | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/Splitio/Services/Common/ISdkEventTask.cs diff --git a/src/Splitio/Services/Common/ISdkEventTask.cs b/src/Splitio/Services/Common/ISdkEventTask.cs deleted file mode 100644 index e2c48145..00000000 --- a/src/Splitio/Services/Common/ISdkEventTask.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Splitio.Domain; -using Splitio.Services.Client.Classes; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Splitio.Services.Common -{ - public interface ISdkEventTask - { - Task OnExecute(SplitClient splitClient, EventMetadata eventMetadata); - } -} From 7b6de44af960514b9ee5386b332df7668dab1628 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 29 Jan 2026 11:19:27 -0800 Subject: [PATCH 77/87] cleanup --- .../Client/Classes/SelfRefreshingClient.cs | 2 +- .../SelfRefreshingBlockUntilReadyService.cs | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 4742a96c..b90e6e74 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -210,7 +210,7 @@ private void BuildManager() private void BuildBlockUntilReadyService() { - _blockUntilReadyService = new SelfRefreshingBlockUntilReadyService(_statusManager, _telemetryInitProducer, _internalEventsTask); + _blockUntilReadyService = new SelfRefreshingBlockUntilReadyService(_statusManager, _telemetryInitProducer); } private void BuildTelemetrySyncTask() diff --git a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs index 542c8f28..f5e9315e 100644 --- a/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs +++ b/src/Splitio/Services/Shared/Classes/SelfRefreshingBlockUntilReadyService.cs @@ -1,8 +1,6 @@ -using Splitio.Domain; -using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Cache.Interfaces; using Splitio.Services.Logger; using Splitio.Services.Shared.Interfaces; -using Splitio.Services.Tasks; using Splitio.Telemetry.Storages; using System; using System.Threading.Tasks; @@ -14,15 +12,12 @@ public class SelfRefreshingBlockUntilReadyService : IBlockUntilReadyService private static readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(SelfRefreshingBlockUntilReadyService)); private readonly IStatusManager _statusManager; - private readonly IInternalEventsTask _internalEventsTask; private readonly ITelemetryInitProducer _telemetryInitProducer; - public SelfRefreshingBlockUntilReadyService(IStatusManager statusManager, ITelemetryInitProducer telemetryInitProducer, - IInternalEventsTask internalEventsTask) + public SelfRefreshingBlockUntilReadyService(IStatusManager statusManager, ITelemetryInitProducer telemetryInitProducer) { _statusManager = statusManager; _telemetryInitProducer = telemetryInitProducer; - _internalEventsTask = internalEventsTask; } public void BlockUntilReady(int blockMilisecondsUntilReady) @@ -53,10 +48,5 @@ public bool IsSdkReady() return false; } } - - public void OnAddToQueueFailed(Task task) - { - _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); - } } } From b7cf44b1d2d925295e81827aa25ef3065e5a2fc7 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 29 Jan 2026 11:42:23 -0800 Subject: [PATCH 78/87] updated version and changes --- CHANGES.txt | 6 ++++++ Splitio.Redis/Splitio.Redis.csproj | 2 +- src/Splitio/Services/Common/EventsManager.cs | 8 ++++---- src/Splitio/Splitio.csproj | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 7b6560cb..f610c04f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,5 +1,11 @@ CHANGES +7.13.0 (Jan 30, 2026) +- Fixed impressions properties format in redis mode. +- Added the ability to listen to different events triggered by the SDK. Read more in our docs. + - SDK_UPDATE notify when a flag or user segment has changed + - SDK_READY notify when the SDK is ready to evaluate + 7.12.0 (Sep 30, 2025) - Added new configuration for Fallback Treatments, which allows setting a treatment value and optional config to be returned in place of "control", either globally or by flag. Read more in our docs. - Added a maximum size payload when posting unique keys telemetry in batches diff --git a/Splitio.Redis/Splitio.Redis.csproj b/Splitio.Redis/Splitio.Redis.csproj index 23a3ee68..ec925af2 100644 --- a/Splitio.Redis/Splitio.Redis.csproj +++ b/Splitio.Redis/Splitio.Redis.csproj @@ -7,7 +7,7 @@ false false false - 7.12.0 + 7.13.0-rc1 true SplitioRedis.snk Apache-2.0 diff --git a/src/Splitio/Services/Common/EventsManager.cs b/src/Splitio/Services/Common/EventsManager.cs index 68cdb526..9ce90a24 100644 --- a/src/Splitio/Services/Common/EventsManager.cs +++ b/src/Splitio/Services/Common/EventsManager.cs @@ -81,21 +81,21 @@ public bool EventAlreadyTriggered(E sdkEvent) } return false; } + #endregion - public bool GetSdkInternalEventStatus(I sdkInternalEvent) + #region Private Methods + private bool GetSdkInternalEventStatus(I sdkInternalEvent) { _internalEventsStatus.TryGetValue(sdkInternalEvent, out var status); return status; } - public void UpdateSdkInternalEventStatus(I sdkInternalEvent, bool status) + private void UpdateSdkInternalEventStatus(I sdkInternalEvent, bool status) { _internalEventsStatus.AddOrUpdate(sdkInternalEvent, status, (_, oldValue) => status); } - #endregion - #region Private Methods private void SetSdkEventTriggered(E sdkEvent) { if (!_activeSubscriptions.TryGetValue(sdkEvent, out var eventData)) diff --git a/src/Splitio/Splitio.csproj b/src/Splitio/Splitio.csproj index f7d09149..95302642 100644 --- a/src/Splitio/Splitio.csproj +++ b/src/Splitio/Splitio.csproj @@ -7,7 +7,7 @@ false false false - 7.12.0 + 7.13.0-rc1 Splitio true Splitio.snk From 92c153bda9d506428bee7296e38de4db28cae7fa Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 29 Jan 2026 13:35:20 -0800 Subject: [PATCH 79/87] moved sdkready fire to sync manager class --- .../Classes/InMemoryReadinessGatesCache.cs | 24 +--------- .../Client/Classes/SelfRefreshingClient.cs | 2 +- .../Services/Client/Classes/SplitClient.cs | 2 +- src/Splitio/Services/Common/SyncManager.cs | 9 ++-- .../TargetingRulesFetcherTests.cs | 6 +-- .../Client/SdkReadinessGatesUnitTests.cs | 47 +------------------ .../Unit Tests/Common/SyncManagerTests.cs | 29 +++++++++++- .../Impressions/ImpressionsCounterTests.cs | 8 ++-- .../SelfRefreshingSegmentFetcherUnitTests.cs | 4 +- .../EventSourceClientTests.cs | 2 +- 10 files changed, 49 insertions(+), 84 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index 637d69df..478325b7 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -1,10 +1,5 @@ -using Splitio.Domain; -using Splitio.Services.Cache.Interfaces; -using Splitio.Services.Logger; -using Splitio.Services.Shared.Classes; -using Splitio.Services.Tasks; +using Splitio.Services.Cache.Interfaces; using System.Threading; -using System.Threading.Tasks; namespace Splitio.Services.Client.Classes { @@ -12,13 +7,8 @@ public class InMemoryReadinessGatesCache : IStatusManager { private readonly CountdownEvent _sdkReady = new CountdownEvent(1); private readonly CountdownEvent _sdkDestroyed = new CountdownEvent(1); - private readonly IInternalEventsTask _internalEventsTask; - private readonly ISplitLogger _log = WrapperAdapter.Instance().GetLogger(typeof(InMemoryReadinessGatesCache)); - public InMemoryReadinessGatesCache(IInternalEventsTask internalEventsTask) - { - _internalEventsTask = internalEventsTask; - } + public InMemoryReadinessGatesCache() {} public bool IsReady() { @@ -33,11 +23,6 @@ public bool WaitUntilReady(int milliseconds) public void SetReady() { _sdkReady.Signal(); - Task task = new Task(() => - { - _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); - }); - task.Start(); } public void SetDestroy() @@ -49,10 +34,5 @@ public bool IsDestroyed() { return _sdkDestroyed.IsSet; } - - public void OnAddToQueueFailed(Task task) - { - _log.Error($"Failed to add internal event to queue: {task.Exception.Message}"); - } } } diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index b90e6e74..072332b7 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -270,7 +270,7 @@ private void BuildSyncManager() // SyncManager var streamingbackoff = new BackOff(_config.StreamingReconnectBackoffBase, attempt: 1); var startupTask = _tasksManager.NewOnTimeTask(Enums.Task.SDKInitialization); - _syncManager = new SyncManager(_config.StreamingEnabled, synchronizer, pushManager, sseHandler, _telemetryRuntimeProducer, _statusManager, _tasksManager, _telemetrySyncTask, streamingbackoff, streamingStatusQueue, startupTask); + _syncManager = new SyncManager(_config.StreamingEnabled, synchronizer, pushManager, sseHandler, _telemetryRuntimeProducer, _statusManager, _tasksManager, _telemetrySyncTask, streamingbackoff, streamingStatusQueue, startupTask, _internalEventsTask); } catch (Exception ex) { diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index ef5867ab..fbbd67dd 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -101,7 +101,7 @@ protected SplitClient(string apikey) _factoryInstantiationsService = FactoryInstantiationsService.Instance(); _flagSetsValidator = new FlagSetsValidator(); _configService = new ConfigService(_wrapperAdapter, _flagSetsValidator, new SdkMetadataValidator()); - _statusManager = new InMemoryReadinessGatesCache(_internalEventsTask); + _statusManager = new InMemoryReadinessGatesCache(); _tasksManager = new TasksManager(_statusManager); } diff --git a/src/Splitio/Services/Common/SyncManager.cs b/src/Splitio/Services/Common/SyncManager.cs index eb70f751..177c41ad 100644 --- a/src/Splitio/Services/Common/SyncManager.cs +++ b/src/Splitio/Services/Common/SyncManager.cs @@ -1,4 +1,5 @@ using Splitio.CommonLibraries; +using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.EventSource; using Splitio.Services.Logger; @@ -11,9 +12,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; -using System.Threading; using System.Threading.Tasks; -using YamlDotNet.Serialization.NodeTypeResolvers; namespace Splitio.Services.Common { @@ -32,6 +31,7 @@ public class SyncManager : ISyncManager, IQueueObserver private readonly IBackOff _backOff; private readonly ISplitTask _startupTask; private readonly SplitQueue _streamingStatusQueue; + private readonly IInternalEventsTask _internalEventsTask; private long _startSessionMs; private bool _streamingOff; @@ -46,7 +46,8 @@ public SyncManager(bool streamingEnabled, ITelemetrySyncTask telemetrySyncTask, IBackOff backOff, SplitQueue streamingStatusQueue, - ISplitTask startupTask) + ISplitTask startupTask, + IInternalEventsTask internalEventsTask) { _streamingEnabled = streamingEnabled; _synchronizer = synchronizer; @@ -60,6 +61,7 @@ public SyncManager(bool streamingEnabled, _backOff = backOff; _streamingStatusQueue = streamingStatusQueue; _streamingStatusQueue.AddObserver(this); + _internalEventsTask = internalEventsTask; _startupTask = startupTask; _startupTask.SetFunction(StartupLogicAsync); } @@ -185,6 +187,7 @@ private async Task StartupLogicAsync() if (_statusManager.IsDestroyed()) return; _statusManager.SetReady(); + await _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null); clock.Stop(); _log.Debug($"Time until SDK ready: {clock.ElapsedMilliseconds} ms."); _telemetrySyncTask.RecordConfigInit(clock.ElapsedMilliseconds); diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index a1fdde68..0f1d7905 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -47,7 +47,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); - var gates = new InMemoryReadinessGatesCache(internalEventsTask); + var gates = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -94,7 +94,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAll var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging_4.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); - var gates = new InMemoryReadinessGatesCache(internalEventsTask); + var gates = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -145,7 +145,7 @@ public async Task ExecuteGetWithoutResults() var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var gates = new InMemoryReadinessGatesCache(internalEventsTask); + var gates = new InMemoryReadinessGatesCache(); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index 9bb6a341..d01d073e 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -1,29 +1,17 @@ -using BitFaster.Caching; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Splitio.Domain; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Services.Client.Classes; -using Splitio.Services.Common; -using Splitio.Services.Shared.Classes; -using Splitio.Services.Tasks; -using System; -using System.Threading; namespace Splitio_Tests.Unit_Tests.Client { [TestClass] public class InMemoryReadinessGatesCacheUnitTests { - private bool SdkReadyFlag = false; - private EventMetadata eMetadata = null; - public event EventHandler SdkReady; [TestMethod] public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() { //Arrange - EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var gates = new InMemoryReadinessGatesCache(internalEventsTask); + var gates = new InMemoryReadinessGatesCache(); //Act var result = gates.IsReady(); @@ -31,36 +19,5 @@ public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() //Assert Assert.IsFalse(result); } - - [TestMethod] - public void TestFireReadyEvent() - { - //Arrange - EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); - var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var gates = new InMemoryReadinessGatesCache(internalEventsTask); - internalEventsTask.Start(); - SdkReady += sdkReady_callback; - eventsManager.Register(SdkEvent.SdkReady, TriggerSdkReady); - - //Act - gates.SetReady(); - SpinWait.SpinUntil(() => SdkReadyFlag, TimeSpan.FromMilliseconds(1000)); - - // Assert. - Assert.IsTrue(SdkReadyFlag); - Assert.AreEqual(null, eMetadata); - } - - private void sdkReady_callback(object sender, EventMetadata metadata) - { - SdkReadyFlag = true; - eMetadata = metadata; - } - - private void TriggerSdkReady(EventMetadata metaData) - { - SdkReady?.Invoke(this, metaData); - } } } diff --git a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs index f6a23814..c1c12f56 100644 --- a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs @@ -24,7 +24,7 @@ public class SyncManagerTests private readonly Mock _statusManager; private readonly Mock _telemetrySyncTask; private readonly Mock _backoff; - + private readonly Mock _internalEventsTask; private readonly SplitQueue _streamingStatusQueue; public SyncManagerTests() @@ -38,6 +38,7 @@ public SyncManagerTests() _telemetrySyncTask = new Mock(); _backoff = new Mock(); _streamingStatusQueue = new SplitQueue(); + _internalEventsTask = new Mock(); } [TestMethod] @@ -232,6 +233,29 @@ public async Task OnProcessFeedbackSSE_STREAMING_BACKOFF() _pushManager.Verify(mock => mock.StartAsync(), Times.Exactly(2)); } + [TestMethod] + public void TestSdkReadyEventIsFiredWhenReady() + { + // Arrange. + _synchronizer + .Setup(mock => mock.SyncAllAsync()) + .ReturnsAsync(true); + + _statusManager + .Setup(mock => mock.IsDestroyed()) + .Returns(false); + + var syncManager = GetSyncManager(false); + + // Act. + syncManager.Start(); + + // Assert. + Thread.Sleep(3000); + _synchronizer.Verify(mock => mock.SyncAllAsync(), Times.Once); + _internalEventsTask.Verify(mock => mock.AddToQueue(Splitio.Domain.SdkInternalEvent.SdkReady, null), Times.Once); + } + private SyncManager GetSyncManager(bool streamingEnabled) { var startupTask = _taskManager.NewOnTimeTask(Splitio.Enums.Task.SDKInitialization); @@ -246,7 +270,8 @@ private SyncManager GetSyncManager(bool streamingEnabled) _telemetrySyncTask.Object, _backoff.Object, _streamingStatusQueue, - startupTask); + startupTask, + _internalEventsTask.Object); } } } diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index 0aa170f7..d9bb1caf 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -32,7 +32,7 @@ public void Start_ShouldSendImpressionsCount() var config = new ComponentConfig(5, 5); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); + var statusManager = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -58,7 +58,7 @@ public void Start_ShouldNotSendImpressionsCount() var config = new ComponentConfig(5, 5); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); + var statusManager = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -79,7 +79,7 @@ public async Task Stop_ShouldSendImpressionsCount() var config = new ComponentConfig(5, 5); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); + var statusManager = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -105,7 +105,7 @@ public async Task ShouldSend2BulksOfImpressions() var config = new ComponentConfig(6, 3); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); + var statusManager = new InMemoryReadinessGatesCache(); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 3b317a03..4debc1c4 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -28,8 +28,8 @@ public void InitializeSegmentNotExistent() // Arrange Mock> eventsManager = new Mock>(); var internalEventsTask = new InternalEventsTask(eventsManager.Object, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); - var gates = new InMemoryReadinessGatesCache(internalEventsTask); + var statusManager = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(); gates.SetReady(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); diff --git a/tests/Splitio.Integration-tests/EventSourceClientTests.cs b/tests/Splitio.Integration-tests/EventSourceClientTests.cs index 65f57d56..2a3b442e 100644 --- a/tests/Splitio.Integration-tests/EventSourceClientTests.cs +++ b/tests/Splitio.Integration-tests/EventSourceClientTests.cs @@ -372,7 +372,7 @@ private static (IEventSourceClient, BlockingCollection, var notificationManagerKeeper = new NotificationManagerKeeper(telemetryRuntimeProducer, streamingStatusQueue); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); + var statusManager = new InMemoryReadinessGatesCache(); var tasksManager = new TasksManager(statusManager); var task = tasksManager.NewOnTimeTask(Enums.Task.SSEConnect); From 2d3758c0ccf190278badbaf2ae4ac6c4e40b8a83 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Thu, 29 Jan 2026 20:11:21 -0800 Subject: [PATCH 80/87] added imp prop to redis impressions --- .../Cache/Classes/RedisImpressionsCache.cs | 7 +++-- .../Impressions/RedisImpressionsCacheTests.cs | 29 +++++++++++++++++-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs b/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs index 28339d4a..b5f9990f 100644 --- a/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs +++ b/Splitio.Redis/Services/Cache/Classes/RedisImpressionsCache.cs @@ -78,12 +78,13 @@ public async Task RecordImpressionsCountAsync(Dictionary impression } } - private RedisValue[] GetImpressions(IList items) + // public for tests + public RedisValue[] GetImpressions(IList items) { - var impressions = items.Select(item => JsonConvertWrapper.SerializeObject(new + var impressions = items.Select(item => JsonConvertWrapper.SerializeObjectIgnoreNullValue(new { m = new { s = SdkVersion, i = MachineIp, n = MachineName }, - i = new { k = item.keyName, b = item.bucketingKey, f = item.feature, t = item.treatment, r = item.label, c = item.changeNumber, m = item.time, pt = item.previousTime } + i = new { k = item.keyName, b = item.bucketingKey, f = item.feature, t = item.treatment, r = item.label, c = item.changeNumber, m = item.time, pt = item.previousTime, properties = item.properties } })); return impressions diff --git a/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs index de5abd43..b1addd5c 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/RedisImpressionsCacheTests.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Splitio.Domain; using Splitio.Redis.Services.Cache.Classes; using Splitio.Redis.Services.Cache.Interfaces; using Splitio.Redis.Services.Domain; @@ -14,8 +15,8 @@ namespace Splitio_Tests.Unit_Tests.Impressions public class RedisImpressionsCacheTests { private Mock _redisAdapter; - - private IImpressionsCache _cache; + + private RedisImpressionsCache _cache; [TestInitialize] public void Initialization() @@ -91,5 +92,29 @@ await _cache.RecordUniqueKeysAsync(new List _redisAdapter.Verify(mock => mock.ListRightPushAsync(key, expected2), Times.Once); _redisAdapter.Verify(mock => mock.KeyExpireAsync(key, new TimeSpan(0, 0, 3600)), Times.Never); } + + [TestMethod] + public void CorrectFormatStoreImpressions() + { + // Arrange. + var impressions = new List + { + new KeyImpression("matching-key", "feature-1", "treatment", 34534546, 3333444, "label", "bucketing-key", false), + new KeyImpression("matching-key", "feature-1", "treatment", 34534550, 3333444, "label", "bucketing-key", false, 34534546), + new KeyImpression("matching-key", "feature-2", "treatment", 34534546, 3333444, "label", "bucketing-key", false), + }; + impressions[2].properties = "{\"prop\":\"val\"}"; + + // Act. + var result = _cache.GetImpressions(impressions); + var impression1 = "{\"m\":{\"s\":\"version\",\"i\":\"ip\",\"n\":\"mm\"},\"i\":{\"k\":\"matching-key\",\"b\":\"bucketing-key\",\"f\":\"feature-1\",\"t\":\"treatment\",\"r\":\"label\",\"c\":3333444,\"m\":34534546}}"; + var impression2 = "{\"m\":{\"s\":\"version\",\"i\":\"ip\",\"n\":\"mm\"},\"i\":{\"k\":\"matching-key\",\"b\":\"bucketing-key\",\"f\":\"feature-1\",\"t\":\"treatment\",\"r\":\"label\",\"c\":3333444,\"m\":34534550,\"pt\":34534546}}"; + var impression3 = "{\"m\":{\"s\":\"version\",\"i\":\"ip\",\"n\":\"mm\"},\"i\":{\"k\":\"matching-key\",\"b\":\"bucketing-key\",\"f\":\"feature-2\",\"t\":\"treatment\",\"r\":\"label\",\"c\":3333444,\"m\":34534546,\"properties\":\"{\\\"prop\\\":\\\"val\\\"}\"}}"; + + // Assert. + Assert.AreEqual(impression1, result[0].ToString()); + Assert.AreEqual(impression2, result[1].ToString()); + Assert.AreEqual(impression3, result[2].ToString()); + } } } From 9efb4363eaf85b8f9a990c23e7fbb772f7cbce76 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Fri, 30 Jan 2026 08:29:33 -0800 Subject: [PATCH 81/87] suggestions --- .../Cache/Classes/InMemoryReadinessGatesCache.cs | 14 +++++++++++--- .../Services/Cache/Interfaces/IStatusManager.cs | 6 ++++-- .../Client/Classes/SelfRefreshingClient.cs | 2 +- src/Splitio/Services/Client/Classes/SplitClient.cs | 2 +- src/Splitio/Services/Common/SyncManager.cs | 11 +++-------- src/Splitio/Services/Tasks/InternalEventsTask.cs | 9 ++++++--- .../TargetingRulesFetcherTests.cs | 6 +++--- .../Cache/InMemory/SegmentCacheAsyncTests.cs | 2 +- .../Unit Tests/Client/LocalhostClientUnitTests.cs | 7 ------- .../Client/SdkReadinessGatesUnitTests.cs | 5 ++++- .../Unit Tests/Common/SyncManagerTests.cs | 3 +-- .../Impressions/ImpressionsCounterTests.cs | 8 ++++---- .../SelfRefreshingSegmentFetcherUnitTests.cs | 7 +++---- .../EventSourceClientTests.cs | 2 +- 14 files changed, 43 insertions(+), 41 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs index 478325b7..f97f08d5 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryReadinessGatesCache.cs @@ -1,5 +1,8 @@ -using Splitio.Services.Cache.Interfaces; +using Splitio.Domain; +using Splitio.Services.Cache.Interfaces; +using Splitio.Services.Tasks; using System.Threading; +using System.Threading.Tasks; namespace Splitio.Services.Client.Classes { @@ -7,8 +10,12 @@ public class InMemoryReadinessGatesCache : IStatusManager { private readonly CountdownEvent _sdkReady = new CountdownEvent(1); private readonly CountdownEvent _sdkDestroyed = new CountdownEvent(1); + private readonly IInternalEventsTask _internalEventsTask; - public InMemoryReadinessGatesCache() {} + public InMemoryReadinessGatesCache(IInternalEventsTask internalEventsTask) + { + _internalEventsTask = internalEventsTask; + } public bool IsReady() { @@ -20,9 +27,10 @@ public bool WaitUntilReady(int milliseconds) return _sdkReady.Wait(milliseconds); } - public void SetReady() + public async Task SetReadyAsync() { _sdkReady.Signal(); + await _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null); } public void SetDestroy() diff --git a/src/Splitio/Services/Cache/Interfaces/IStatusManager.cs b/src/Splitio/Services/Cache/Interfaces/IStatusManager.cs index ebfe0ffe..c27475db 100644 --- a/src/Splitio/Services/Cache/Interfaces/IStatusManager.cs +++ b/src/Splitio/Services/Cache/Interfaces/IStatusManager.cs @@ -1,10 +1,12 @@ -namespace Splitio.Services.Cache.Interfaces +using System.Threading.Tasks; + +namespace Splitio.Services.Cache.Interfaces { public interface IStatusManager { bool IsReady(); bool WaitUntilReady(int milliseconds); - void SetReady(); + Task SetReadyAsync(); void SetDestroy(); bool IsDestroyed(); } diff --git a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs index 072332b7..b90e6e74 100644 --- a/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs +++ b/src/Splitio/Services/Client/Classes/SelfRefreshingClient.cs @@ -270,7 +270,7 @@ private void BuildSyncManager() // SyncManager var streamingbackoff = new BackOff(_config.StreamingReconnectBackoffBase, attempt: 1); var startupTask = _tasksManager.NewOnTimeTask(Enums.Task.SDKInitialization); - _syncManager = new SyncManager(_config.StreamingEnabled, synchronizer, pushManager, sseHandler, _telemetryRuntimeProducer, _statusManager, _tasksManager, _telemetrySyncTask, streamingbackoff, streamingStatusQueue, startupTask, _internalEventsTask); + _syncManager = new SyncManager(_config.StreamingEnabled, synchronizer, pushManager, sseHandler, _telemetryRuntimeProducer, _statusManager, _tasksManager, _telemetrySyncTask, streamingbackoff, streamingStatusQueue, startupTask); } catch (Exception ex) { diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index fbbd67dd..ef5867ab 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -101,7 +101,7 @@ protected SplitClient(string apikey) _factoryInstantiationsService = FactoryInstantiationsService.Instance(); _flagSetsValidator = new FlagSetsValidator(); _configService = new ConfigService(_wrapperAdapter, _flagSetsValidator, new SdkMetadataValidator()); - _statusManager = new InMemoryReadinessGatesCache(); + _statusManager = new InMemoryReadinessGatesCache(_internalEventsTask); _tasksManager = new TasksManager(_statusManager); } diff --git a/src/Splitio/Services/Common/SyncManager.cs b/src/Splitio/Services/Common/SyncManager.cs index 177c41ad..4fee070e 100644 --- a/src/Splitio/Services/Common/SyncManager.cs +++ b/src/Splitio/Services/Common/SyncManager.cs @@ -1,5 +1,4 @@ using Splitio.CommonLibraries; -using Splitio.Domain; using Splitio.Services.Cache.Interfaces; using Splitio.Services.EventSource; using Splitio.Services.Logger; @@ -31,8 +30,7 @@ public class SyncManager : ISyncManager, IQueueObserver private readonly IBackOff _backOff; private readonly ISplitTask _startupTask; private readonly SplitQueue _streamingStatusQueue; - private readonly IInternalEventsTask _internalEventsTask; - + private long _startSessionMs; private bool _streamingOff; @@ -46,8 +44,7 @@ public SyncManager(bool streamingEnabled, ITelemetrySyncTask telemetrySyncTask, IBackOff backOff, SplitQueue streamingStatusQueue, - ISplitTask startupTask, - IInternalEventsTask internalEventsTask) + ISplitTask startupTask) { _streamingEnabled = streamingEnabled; _synchronizer = synchronizer; @@ -61,7 +58,6 @@ public SyncManager(bool streamingEnabled, _backOff = backOff; _streamingStatusQueue = streamingStatusQueue; _streamingStatusQueue.AddObserver(this); - _internalEventsTask = internalEventsTask; _startupTask = startupTask; _startupTask.SetFunction(StartupLogicAsync); } @@ -186,8 +182,7 @@ private async Task StartupLogicAsync() if (_statusManager.IsDestroyed()) return; - _statusManager.SetReady(); - await _internalEventsTask.AddToQueue(SdkInternalEvent.SdkReady, null); + await _statusManager.SetReadyAsync(); clock.Stop(); _log.Debug($"Time until SDK ready: {clock.ElapsedMilliseconds} ms."); _telemetrySyncTask.RecordConfigInit(clock.ElapsedMilliseconds); diff --git a/src/Splitio/Services/Tasks/InternalEventsTask.cs b/src/Splitio/Services/Tasks/InternalEventsTask.cs index f0534dbe..8e86f5f1 100644 --- a/src/Splitio/Services/Tasks/InternalEventsTask.cs +++ b/src/Splitio/Services/Tasks/InternalEventsTask.cs @@ -45,10 +45,13 @@ public async Task Notify() { try { - if (!_queue.TryDequeue(out SdkEventNotification sdkEventDto)) return; + await Task.Run(() => + { + if (!_queue.TryDequeue(out SdkEventNotification sdkEventDto)) return; - _logger.Debug($"InternalEventTask: SdkEvent dequeue: {sdkEventDto.SdkInternalEvent}"); - _eventsManager.NotifyInternalEvent(sdkEventDto.SdkInternalEvent, sdkEventDto.EventMetadata); + _logger.Debug($"InternalEventTask: SdkEvent dequeue: {sdkEventDto.SdkInternalEvent}"); + _eventsManager.NotifyInternalEvent(sdkEventDto.SdkInternalEvent, sdkEventDto.EventMetadata); + }); } catch (Exception ex) { diff --git a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs index 0f1d7905..a1fdde68 100644 --- a/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs +++ b/tests/Splitio-tests/Integration Tests/TargetingRulesFetcherTests.cs @@ -47,7 +47,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFile() var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -94,7 +94,7 @@ public async Task ExecuteGetSuccessfulWithResultsFromJSONFileIncludingTrafficAll var splitChangeFetcher = new JSONFileSplitChangeFetcher($"{rootFilePath}splits_staging_4.json"); var flagSetsFilter = new FlagSetsFilter(new HashSet()); var splitCache = new InMemorySplitCache(new ConcurrentDictionary(), flagSetsFilter, internalEventsTask); - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(gates); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.FeatureFlagsFetcher, 250); var featureFlagSyncService = new FeatureFlagUpdater(splitParser, splitCache, flagSetsFilter, rbsCache); @@ -145,7 +145,7 @@ public async Task ExecuteGetWithoutResults() var apiSegmentChangeFetcher = new ApiSegmentChangeFetcher(sdkSegmentApiClient); var eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var gates = new InMemoryReadinessGatesCache(); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); var segmentCache = new InMemorySegmentCache(new ConcurrentDictionary(), internalEventsTask); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs index 60bae8f3..bced73ee 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SegmentCacheAsyncTests.cs @@ -62,7 +62,7 @@ public async Task IsInSegmentAsyncTestTrue() } [TestMethod] - public async Task NotifyEventsTest() + public void NotifyEventsTest() { //Arrange var segmentName = "segment_test"; diff --git a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs index 4609cd16..66a76331 100644 --- a/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/LocalhostClientUnitTests.cs @@ -1,8 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Splitio.Domain; using Splitio.Services.Client.Classes; -using Splitio.Services.Common; -using Splitio.Services.Impressions.Classes; using Splitio.Services.Shared.Classes; namespace Splitio_Tests.Unit_Tests.Client @@ -11,16 +9,11 @@ namespace Splitio_Tests.Unit_Tests.Client public class LocalhostClientUnitTests { private readonly string rootFilePath; - private readonly FallbackTreatmentCalculator _fallbackTreatmentCalculator; - private readonly EventsManager _eventsManager; - private bool SdkReady = false; public LocalhostClientUnitTests() { // This line is to clean the warnings. rootFilePath = string.Empty; - _fallbackTreatmentCalculator = new FallbackTreatmentCalculator(new FallbackTreatmentsConfiguration()); - _eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); #if NET_LATEST rootFilePath = @"Resources\"; diff --git a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs index d01d073e..0d4a8f87 100644 --- a/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/Client/SdkReadinessGatesUnitTests.cs @@ -1,5 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; using Splitio.Services.Client.Classes; +using Splitio.Services.Tasks; namespace Splitio_Tests.Unit_Tests.Client { @@ -11,7 +13,8 @@ public class InMemoryReadinessGatesCacheUnitTests public void IsSDKReadyShouldReturnFalseIfSplitsAreNotReady() { //Arrange - var gates = new InMemoryReadinessGatesCache(); + var internalEventsTask = new Mock(); + var gates = new InMemoryReadinessGatesCache(internalEventsTask.Object); //Act var result = gates.IsReady(); diff --git a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs index c1c12f56..205f45ec 100644 --- a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs @@ -270,8 +270,7 @@ private SyncManager GetSyncManager(bool streamingEnabled) _telemetrySyncTask.Object, _backoff.Object, _streamingStatusQueue, - startupTask, - _internalEventsTask.Object); + startupTask); } } } diff --git a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs index d9bb1caf..0aa170f7 100644 --- a/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs +++ b/tests/Splitio-tests/Unit Tests/Impressions/ImpressionsCounterTests.cs @@ -32,7 +32,7 @@ public void Start_ShouldSendImpressionsCount() var config = new ComponentConfig(5, 5); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -58,7 +58,7 @@ public void Start_ShouldNotSendImpressionsCount() var config = new ComponentConfig(5, 5); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 1); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -79,7 +79,7 @@ public async Task Stop_ShouldSendImpressionsCount() var config = new ComponentConfig(5, 5); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); @@ -105,7 +105,7 @@ public async Task ShouldSend2BulksOfImpressions() var config = new ComponentConfig(6, 3); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var taskManager = new TasksManager(statusManager); var task = taskManager.NewPeriodicTask(Splitio.Enums.Task.ImpressionsCountSender, 100); var sendBulkDataTask = taskManager.NewOnTimeTask(Splitio.Enums.Task.ImpressionCounterSendBulkData); diff --git a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 4debc1c4..4bf0e94b 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -23,14 +23,13 @@ public class SelfRefreshingSegmentFetcherUnitTests private static readonly string PayedSplitJson = @"{'name': 'payed','added': ['abcdz','bcadz','xzydz'],'removed': [],'since': -1,'till': 10001}"; [TestMethod] - public void InitializeSegmentNotExistent() + public async Task InitializeSegmentNotExistent() { // Arrange Mock> eventsManager = new Mock>(); var internalEventsTask = new InternalEventsTask(eventsManager.Object, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(); - var gates = new InMemoryReadinessGatesCache(); - gates.SetReady(); + var gates = new InMemoryReadinessGatesCache(internalEventsTask); + await gates.SetReadyAsync(); var apiClient = new Mock(); var apiFetcher = new ApiSegmentChangeFetcher(apiClient.Object); var segments = new ConcurrentDictionary(); diff --git a/tests/Splitio.Integration-tests/EventSourceClientTests.cs b/tests/Splitio.Integration-tests/EventSourceClientTests.cs index 2a3b442e..65f57d56 100644 --- a/tests/Splitio.Integration-tests/EventSourceClientTests.cs +++ b/tests/Splitio.Integration-tests/EventSourceClientTests.cs @@ -372,7 +372,7 @@ private static (IEventSourceClient, BlockingCollection, var notificationManagerKeeper = new NotificationManagerKeeper(telemetryRuntimeProducer, streamingStatusQueue); EventsManager eventsManager = new EventsManager(new EventsManagerConfig(), new EventDelivery()); var internalEventsTask = new InternalEventsTask(eventsManager, new SplitQueue()); - var statusManager = new InMemoryReadinessGatesCache(); + var statusManager = new InMemoryReadinessGatesCache(internalEventsTask); var tasksManager = new TasksManager(statusManager); var task = tasksManager.NewOnTimeTask(Enums.Task.SSEConnect); From f9d8f892e7da68350e7964449c1a1ee45541d0e2 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Fri, 30 Jan 2026 08:35:19 -0800 Subject: [PATCH 82/87] update internalEvents --- .../Services/Tasks/InternalEventsTask.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Splitio/Services/Tasks/InternalEventsTask.cs b/src/Splitio/Services/Tasks/InternalEventsTask.cs index 8e86f5f1..411aa73b 100644 --- a/src/Splitio/Services/Tasks/InternalEventsTask.cs +++ b/src/Splitio/Services/Tasks/InternalEventsTask.cs @@ -43,22 +43,22 @@ public async Task AddToQueue(SdkInternalEvent sdkInternalEvent, EventMetadata ev public async Task Notify() { - try + await Task.Run(() => { - await Task.Run(() => + try { if (!_queue.TryDequeue(out SdkEventNotification sdkEventDto)) return; _logger.Debug($"InternalEventTask: SdkEvent dequeue: {sdkEventDto.SdkInternalEvent}"); _eventsManager.NotifyInternalEvent(sdkEventDto.SdkInternalEvent, sdkEventDto.EventMetadata); - }); - } - catch (Exception ex) - { - if (ex is OperationCanceledException) return; + } + catch (Exception ex) + { + if (ex is OperationCanceledException) return; - _logger.Debug($"InternalEventTask worker Execute exception", ex); - } + _logger.Debug($"InternalEventTask worker Execute exception", ex); + } + }); } } } From f8a19536ba89aaaedccfdceefd8d56dcda85938b Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 30 Jan 2026 09:03:50 -0800 Subject: [PATCH 83/87] removed event test from sync manager --- .../Unit Tests/Common/SyncManagerTests.cs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs index 205f45ec..372e4429 100644 --- a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs @@ -233,29 +233,6 @@ public async Task OnProcessFeedbackSSE_STREAMING_BACKOFF() _pushManager.Verify(mock => mock.StartAsync(), Times.Exactly(2)); } - [TestMethod] - public void TestSdkReadyEventIsFiredWhenReady() - { - // Arrange. - _synchronizer - .Setup(mock => mock.SyncAllAsync()) - .ReturnsAsync(true); - - _statusManager - .Setup(mock => mock.IsDestroyed()) - .Returns(false); - - var syncManager = GetSyncManager(false); - - // Act. - syncManager.Start(); - - // Assert. - Thread.Sleep(3000); - _synchronizer.Verify(mock => mock.SyncAllAsync(), Times.Once); - _internalEventsTask.Verify(mock => mock.AddToQueue(Splitio.Domain.SdkInternalEvent.SdkReady, null), Times.Once); - } - private SyncManager GetSyncManager(bool streamingEnabled) { var startupTask = _taskManager.NewOnTimeTask(Splitio.Enums.Task.SDKInitialization); From b34174f299d13ca69dc55cbec1cfceb59d15b762 Mon Sep 17 00:00:00 2001 From: Mauro Sanz Date: Fri, 30 Jan 2026 09:13:08 -0800 Subject: [PATCH 84/87] cleanup --- tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs index 372e4429..f6787387 100644 --- a/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs +++ b/tests/Splitio-tests/Unit Tests/Common/SyncManagerTests.cs @@ -24,7 +24,6 @@ public class SyncManagerTests private readonly Mock _statusManager; private readonly Mock _telemetrySyncTask; private readonly Mock _backoff; - private readonly Mock _internalEventsTask; private readonly SplitQueue _streamingStatusQueue; public SyncManagerTests() @@ -38,7 +37,6 @@ public SyncManagerTests() _telemetrySyncTask = new Mock(); _backoff = new Mock(); _streamingStatusQueue = new SplitQueue(); - _internalEventsTask = new Mock(); } [TestMethod] From b3464e4387646636e825e39c76fc53fcca3cef1b Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 30 Jan 2026 22:29:15 -0800 Subject: [PATCH 85/87] prevent event fire with only changenumber update --- .../Cache/Classes/InMemoryRuleBasedSegmentCache.cs | 13 ++++++++----- .../Services/Cache/Classes/InMemorySplitCache.cs | 13 ++++++++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs index 14de743a..3aeaef60 100644 --- a/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemoryRuleBasedSegmentCache.cs @@ -63,12 +63,15 @@ public void Update(List toAdd, List toRemove, long til } SetChangeNumber(till); - Task task = new Task(() => + if (toAdd.Count > 0 || toRemove.Count > 0) { - _internalEventsTask.AddToQueue(SdkInternalEvent.RuleBasedSegmentsUpdated, - new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); - }); - task.Start(); + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.RuleBasedSegmentsUpdated, + new EventMetadata(SdkEventType.SegmentsUpdate, new List())).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); + } } public void SetChangeNumber(long changeNumber) diff --git a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs index b88ba7e4..6063d43e 100644 --- a/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs +++ b/src/Splitio/Services/Cache/Classes/InMemorySplitCache.cs @@ -78,12 +78,15 @@ public void Update(List toAdd, List toRemove, long till) } SetChangeNumber(till); - Task task = new Task(() => + if (eventsFlags.Any()) { - _internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, - new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); - }); - task.Start(); + Task task = new Task(() => + { + _internalEventsTask.AddToQueue(SdkInternalEvent.FlagsUpdated, + new EventMetadata(SdkEventType.FlagsUpdate, eventsFlags)).ContinueWith(OnAddToQueueFailed, TaskContinuationOptions.OnlyOnFaulted); + }); + task.Start(); + } } public void SetChangeNumber(long changeNumber) From 62f55e36a21832d2bdb72ef357d642f267f4ae83 Mon Sep 17 00:00:00 2001 From: Bill Al Date: Fri, 30 Jan 2026 22:39:56 -0800 Subject: [PATCH 86/87] added tests --- .../Cache/InMemory/RuleBasedSegmentCacheTests.cs | 7 +++++++ .../Unit Tests/Cache/InMemory/SplitCacheTests.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs index eb6739bf..5a3a06af 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/RuleBasedSegmentCacheTests.cs @@ -178,6 +178,13 @@ public void Update_ShouldNotifyEvent() // Assert Assert.IsTrue(SdkUpdateFlag); Assert.AreEqual(SdkEventType.SegmentsUpdate, eMetadata.GetEventType()); + + // Act + SdkUpdateFlag = false; + _segmentCache.Update(new List(), new List(), 12345); + + // Assert + Assert.IsFalse(SdkUpdateFlag); } private void sdkUpdate_callback(object sender, EventMetadata metadata) diff --git a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs index a07c9370..cb845055 100644 --- a/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs +++ b/tests/Splitio-tests/Unit Tests/Cache/InMemory/SplitCacheTests.cs @@ -281,6 +281,13 @@ public void NotifyUpdateEventTest() Assert.AreEqual(SdkEventType.FlagsUpdate, eMetadata.GetEventType()); Assert.IsTrue(eMetadata.GetNames().Count == 1); Assert.IsTrue(eMetadata.GetNames().Contains(splitName)); + + // Act. + SdkUpdateFlag = false; + splitCache.Update(new List(), new List(), 1234); + + // Assert. + Assert.IsFalse(SdkUpdateFlag); } private void sdkUpdate_callback(object sender, EventMetadata metadata) From 9244bb4d747f38f84393bd4a86ac57c78f926c7a Mon Sep 17 00:00:00 2001 From: Bill Al Date: Sun, 1 Feb 2026 19:55:59 -0800 Subject: [PATCH 87/87] updated changes and added notice --- CHANGES.txt | 2 +- NOTICE.txt | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 NOTICE.txt diff --git a/CHANGES.txt b/CHANGES.txt index f610c04f..be901588 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,6 @@ CHANGES -7.13.0 (Jan 30, 2026) +7.13.0 (Feb 2, 2026) - Fixed impressions properties format in redis mode. - Added the ability to listen to different events triggered by the SDK. Read more in our docs. - SDK_UPDATE notify when a flag or user segment has changed diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 00000000..d0ea3bf0 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,5 @@ +Harness Feature Management .NET SDK Copyright 2024-2026 Harness Inc. + +This product includes software developed at Harness Inc. (https://harness.io/). + +This product includes software originally developed by Split Software, Inc. (https://www.split.io/). Copyright 2015-2024 Split Software, Inc.