diff --git a/src/Splitio/Services/Client/Classes/SplitClient.cs b/src/Splitio/Services/Client/Classes/SplitClient.cs index 82c99b1e..1d00ef41 100644 --- a/src/Splitio/Services/Client/Classes/SplitClient.cs +++ b/src/Splitio/Services/Client/Classes/SplitClient.cs @@ -63,9 +63,24 @@ public abstract class SplitClient : ISplitClient protected IImpressionsObserver _impressionsObserver; protected IClientExtensionService _clientExtensionService; protected IFlagSetsFilter _flagSetsFilter; - protected IEventsManager _eventsManager; + 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); + } + } - public event EventHandler SdkReady; + remove + { + SdkReadyEvent = (EventHandler)Delegate.Remove(SdkReadyEvent, value); + } + } public event EventHandler SdkUpdate; public event EventHandler SdkTimedOut; @@ -74,11 +89,8 @@ 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(); @@ -309,6 +321,7 @@ public virtual async Task DestroyAsync() _factoryInstantiationsService.Decrease(ApiKey); _statusManager.SetDestroy(); await _syncManager.ShutdownAsync(); + UnregisterEvents(); _log.Info(Messages.Destroyed); } @@ -322,6 +335,7 @@ public virtual void Destroy() _factoryInstantiationsService.Decrease(ApiKey); _statusManager.SetDestroy(); _syncManager.Shutdown(); + UnregisterEvents(); _log.Info(Messages.Destroyed); } @@ -492,6 +506,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 @@ -580,19 +606,19 @@ private static SplitResult TreatmentWithConfig(List results) return new SplitResult(result.Treatment, result.Config); } - private void TriggerSdkReadyEvent(EventMetadata metadata) + private void TriggerSdkReady(EventMetadata metaData) { - SdkReady?.Invoke(this, metadata); + SdkReadyEvent?.Invoke(this, metaData); } - private void TriggerSdkUpdateEvent(EventMetadata metadata) + private void TriggerSdkUpdate(EventMetadata metaData) { - SdkUpdate?.Invoke(this, metadata); + SdkUpdate?.Invoke(this, metaData); } - private void TriggerSdkTimeoutEvent(EventMetadata metadata) + private void TriggerSdkTimeout(EventMetadata metaData) { - SdkTimedOut?.Invoke(this, metadata); + SdkTimedOut?.Invoke(this, metaData); } #endregion } 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/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs index 2b845698..c1b9ce49 100644 --- a/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs +++ b/tests/Splitio-tests/Unit Tests/SegmentFetcher/SelfRefreshingSegmentFetcherUnitTests.cs @@ -10,6 +10,7 @@ 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; @@ -26,12 +27,12 @@ public class SelfRefreshingSegmentFetcherUnitTests public void InitializeSegmentNotExistent() { // Arrange - var gates = new InMemoryReadinessGatesCache(new EventsManager(new EventsManagerConfig(), new EventDelivery())); + 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(); - Mock> eventsManager = new Mock>(); var cache = new InMemorySegmentCache(segments, eventsManager.Object); var segmentsQueue = new SplitQueue(); var taskManager = new TasksManager(gates); 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 6dab8142..d9925b28 100644 --- a/tests/Splitio.Integration-tests/StreamingClientTests.cs +++ b/tests/Splitio.Integration-tests/StreamingClientTests.cs @@ -22,10 +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; + private bool SdkReady = false; + private bool SdkReady2 = false; + private bool SdkReady3 = false; + private bool SdkUpdate = false; [TestMethod] public void GetTreatment_SplitUpdate_ShouldFetch() @@ -60,7 +60,8 @@ 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"; @@ -68,13 +69,18 @@ public void GetTreatment_SplitUpdate_ShouldFetch() 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(SdkReadyFlag); - Assert.IsTrue(SdkReadyFlag2); + Assert.IsTrue(SdkReady); + Assert.IsTrue(SdkReady2); + Assert.IsTrue(SdkReady3); + Assert.IsTrue(SdkUpdate); client.Destroy(); } @@ -119,13 +125,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(); } } @@ -774,12 +778,22 @@ public static string EvaluateWithDelay(string key, string splitName, string expe private void sdkReady_callback(object sender, EventMetadata metadata) { - SdkReadyFlag = true; + SdkReady = true; } private void sdkReady_callback2(object sender, EventMetadata metadata) { - SdkReadyFlag2 = true; + SdkReady2 = true; + } + + private void sdkReady_callback3(object sender, EventMetadata metadata) + { + SdkReady3 = true; + } + + private void sdkUpdate_callback(object sender, EventMetadata metadata) + { + SdkUpdate = true; } } }