public DataSourceUpdatesImplTest(ITestOutputHelper testOutput) : base(testOutput) { taskExecutor = new TaskExecutor(testLogger); store = new InMemoryDataStore(); dataStoreUpdates = new DataStoreUpdatesImpl(taskExecutor); dataStoreStatusProvider = new DataStoreStatusProviderImpl(store, dataStoreUpdates); }
public StreamProcessorTest(ITestOutputHelper testOutput) : base(testOutput) { _mockEventSource = new Mock <IEventSource>(); _mockEventSource.Setup(es => es.StartAsync()).Returns(Task.CompletedTask).Callback(() => _esStartedReady.Set()); _eventSource = _mockEventSource.Object; _eventSourceFactory = new TestEventSourceFactory(_eventSource); _dataStore = new DelegatingDataStoreForStreamTests { WrappedStore = new InMemoryDataStore() }; _dataStoreUpdates = new DataStoreUpdatesImpl(new TaskExecutor(testLogger)); _dataStoreStatusProvider = new DataStoreStatusProviderImpl(_dataStore, _dataStoreUpdates); _dataSourceUpdates = new DataSourceUpdatesImpl( _dataStore, _dataStoreStatusProvider, new TaskExecutor(testLogger), testLogger, null ); _dataSourceStatusProvider = new DataSourceStatusProviderImpl(_dataSourceUpdates); _config = Configuration.Builder(SDK_KEY) .DataSource(Components.StreamingDataSource().EventSourceCreator(_eventSourceFactory.Create())) .DataStore(TestUtils.SpecificDataStore(_dataStore)) .Logging(Components.Logging(testLogging)) .Build(); }
public StreamProcessorTest(ITestOutputHelper testOutput) : base(testOutput) { _mockEventSource = new Mock <IEventSource>(); _mockEventSource.Setup(es => es.StartAsync()).Returns(TestUtils.CompletedTask()).Callback(() => _esStartedReady.Set()); _eventSource = _mockEventSource.Object; _eventSourceFactory = new TestEventSourceFactory(_eventSource); _dataStore = new DelegatingDataStoreForStreamTests { WrappedStore = new InMemoryDataStore() }; _dataStoreUpdates = new DataStoreUpdatesImpl(BasicTaskExecutor, TestLogger); _dataStoreStatusProvider = new DataStoreStatusProviderImpl(_dataStore, _dataStoreUpdates); _dataSourceUpdates = new DataSourceUpdatesImpl( _dataStore, _dataStoreStatusProvider, BasicTaskExecutor, TestLogger, null ); _dataSourceStatusProvider = new DataSourceStatusProviderImpl(_dataSourceUpdates); _config = BasicConfig() .DataSource(Components.StreamingDataSource().EventSourceCreator(_eventSourceFactory.Create())) .DataStore(_dataStore.AsSingletonFactory()) .Build(); }
/// <summary> /// Creates a new client to connect to LaunchDarkly with a custom configuration. /// </summary> /// <remarks> /// <para> /// Applications should instantiate a single instance for the lifetime of the application. In /// unusual cases where an application needs to evaluate feature flags from different LaunchDarkly /// projects or environments, you may create multiple clients, but they should still be retained /// for the lifetime of the application rather than created per request or per thread. /// </para> /// <para> /// Normally, the client will begin attempting to connect to LaunchDarkly as soon as you call the /// constructor. The constructor returns as soon as any of the following things has happened: /// </para> /// <list type="number"> /// <item><description> It has successfully connected to LaunchDarkly and received feature flag data. In this /// case, <see cref="Initialized"/> will be true, and the <see cref="DataSourceStatusProvider"/> /// will return a state of <see cref="DataSourceState.Valid"/>. </description></item> /// <item><description> It has not succeeded in connecting within the <see cref="ConfigurationBuilder.StartWaitTime(TimeSpan)"/> /// timeout (the default for this is 5 seconds). This could happen due to a network problem or a /// temporary service outage. In this case, <see cref="Initialized"/> will be false, and the /// <see cref="DataSourceStatusProvider"/> will return a state of <see cref="DataSourceState.Initializing"/>, /// indicating that the SDK will still continue trying to connect in the background. </description></item> /// <item><description> It has encountered an unrecoverable error: for instance, LaunchDarkly has rejected the /// SDK key. Since an invalid key will not become valid, the SDK will not retry in this case. /// <see cref="Initialized"/> will be false, and the <see cref="DataSourceStatusProvider"/> will /// return a state of <see cref="DataSourceState.Off"/>. </description></item> /// </list> /// <para> /// If you have specified <see cref="ConfigurationBuilder.Offline"/> mode or /// <see cref="Components.ExternalUpdatesOnly"/>, the constructor returns immediately without /// trying to connect to LaunchDarkly. /// </para> /// <para> /// Failure to connect to LaunchDarkly will never cause the constructor to throw an exception. /// Under any circumstance where it is not able to get feature flag data from LaunchDarkly (and /// therefore <see cref="Initialized"/> is false), if it does not have any other source of data /// (such as a persistent data store) then feature flag evaluations will behave the same as if /// the flags were not found: that is, they will return whatever default value is specified in /// your code. /// </para> /// </remarks> /// <param name="config">a client configuration object (which includes an SDK key)</param> /// <example> /// <code> /// var config = Configuration.Builder("my-sdk-key") /// .AllAttributesPrivate(true) /// .EventCapacity(1000) /// .Build(); /// var client = new LDClient(config); /// </code> /// </example> /// <seealso cref="LdClient.LdClient(string)"/> public LdClient(Configuration config) { _configuration = config; var logConfig = (config.LoggingConfigurationFactory ?? Components.Logging()) .CreateLoggingConfiguration(); _log = logConfig.LogAdapter.Logger(logConfig.BaseLoggerName ?? LogNames.DefaultBase); _log.Info("Starting LaunchDarkly client {0}", AssemblyVersions.GetAssemblyVersionStringForType(typeof(LdClient))); _evalLog = _log.SubLogger(LogNames.EvaluationSubLog); var basicConfig = new BasicConfiguration(config, _log); var httpConfig = (config.HttpConfigurationFactory ?? Components.HttpConfiguration()) .CreateHttpConfiguration(basicConfig); ServerDiagnosticStore diagnosticStore = _configuration.DiagnosticOptOut ? null : new ServerDiagnosticStore(_configuration, basicConfig, httpConfig); var taskExecutor = new TaskExecutor(this, _log); var clientContext = new LdClientContext(basicConfig, httpConfig, diagnosticStore, taskExecutor); var dataStoreUpdates = new DataStoreUpdatesImpl(taskExecutor, _log.SubLogger(LogNames.DataStoreSubLog)); _dataStore = (_configuration.DataStoreFactory ?? Components.InMemoryDataStore) .CreateDataStore(clientContext, dataStoreUpdates); _dataStoreStatusProvider = new DataStoreStatusProviderImpl(_dataStore, dataStoreUpdates); var bigSegmentsConfig = (_configuration.BigSegmentsConfigurationFactory ?? Components.BigSegments(null)) .CreateBigSegmentsConfiguration(clientContext); _bigSegmentStoreWrapper = bigSegmentsConfig.Store is null ? null : new BigSegmentStoreWrapper( bigSegmentsConfig, taskExecutor, _log.SubLogger(LogNames.BigSegmentsSubLog) ); _bigSegmentStoreStatusProvider = new BigSegmentStoreStatusProviderImpl(_bigSegmentStoreWrapper); _evaluator = new Evaluator( GetFlag, GetSegment, _bigSegmentStoreWrapper == null ? (Func <string, BigSegmentsInternalTypes.BigSegmentsQueryResult>)null : _bigSegmentStoreWrapper.GetUserMembership, _log ); var eventProcessorFactory = config.Offline ? Components.NoEvents : (_configuration.EventProcessorFactory ?? Components.SendEvents()); _eventProcessor = eventProcessorFactory.CreateEventProcessor(clientContext); var dataSourceUpdates = new DataSourceUpdatesImpl(_dataStore, _dataStoreStatusProvider, taskExecutor, _log, logConfig.LogDataSourceOutageAsErrorAfter); IDataSourceFactory dataSourceFactory = config.Offline ? Components.ExternalUpdatesOnly : (_configuration.DataSourceFactory ?? Components.StreamingDataSource()); _dataSource = dataSourceFactory.CreateDataSource(clientContext, dataSourceUpdates); _dataSourceStatusProvider = new DataSourceStatusProviderImpl(dataSourceUpdates); _flagTracker = new FlagTrackerImpl(dataSourceUpdates, (string key, User user) => JsonVariation(key, user, LdValue.Null)); var initTask = _dataSource.Start(); if (!(_dataSource is ComponentsImpl.NullDataSource)) { _log.Info("Waiting up to {0} milliseconds for LaunchDarkly client to start...", _configuration.StartWaitTime.TotalMilliseconds); } try { var success = initTask.Wait(_configuration.StartWaitTime); if (!success) { _log.Warn("Timeout encountered waiting for LaunchDarkly client initialization"); } } catch (AggregateException) { // StreamProcessor may throw an exception if initialization fails, because we want that behavior // in the Xamarin client. However, for backward compatibility we do not want to throw exceptions // from the LdClient constructor in the .NET client, so we'll just swallow this. } }