private void TestDiagnosticConfig( Func <ConfigurationBuilder, ConfigurationBuilder> modConfig, Func <EventProcessorBuilder, EventProcessorBuilder> modEvents, LdValue.ObjectBuilder expected ) { var eventsBuilder = Components.SendEvents() .EventSender(testEventSender); modEvents?.Invoke(eventsBuilder); var configBuilder = BasicConfig() .DataSource(null) .Events(eventsBuilder) .Http(Components.HttpConfiguration().MessageHandler(new StubMessageHandler(HttpStatusCode.Unauthorized))) .StartWaitTime(testStartWaitTime); configBuilder = modConfig is null ? configBuilder : modConfig(configBuilder); using (var client = new LdClient(configBuilder.Build())) { var payload = testEventSender.RequirePayload(); Assert.Equal(EventDataKind.DiagnosticEvent, payload.Kind); Assert.Equal(1, payload.EventCount); var data = JsonOf(payload.Data); AssertJsonEqual(JsonFromValue("diagnostic-init"), data.Property("kind")); AssertJsonEqual(JsonOf(expected.Build().ToJsonString()), data.Property("configuration")); } }
public void DiagnosticInitEventIsSent() { var config = BasicConfig() .Events(Components.SendEvents().EventSender(testEventSender)) .Http( Components.HttpConfiguration().Wrapper(testWrapperName, testWrapperVersion) ) .Build(); using (var client = new LdClient(config)) { var payload = testEventSender.RequirePayload(); Assert.Equal(EventDataKind.DiagnosticEvent, payload.Kind); Assert.Equal(1, payload.EventCount); var data = JsonOf(payload.Data); AssertJsonEqual(JsonFromValue("diagnostic-init"), data.Property("kind")); AssertJsonEqual(JsonFromValue("dotnet"), data.RequiredProperty("platform").Property("name")); AssertJsonEqual(JsonFromValue(ServerDiagnosticStore.GetDotNetTargetFramework()), data.RequiredProperty("platform").Property("dotNetTargetFramework")); AssertJsonEqual(expectedSdk, data.Property("sdk")); AssertJsonEqual(JsonFromValue("dk-key"), data.Property("id").Property("sdkKeySuffix")); data.RequiredProperty("creationDate"); } }
public void DiagnosticInitEventIsSent() { var config = Configuration.Builder(sdkKey) .DataSource(Components.ExternalUpdatesOnly) .Events(Components.SendEvents().EventSender(testEventSender)) .Http( Components.HttpConfiguration().Wrapper(testWrapperName, testWrapperVersion) ) .Logging(Components.Logging(testLogging)) .Build(); using (var client = new LdClient(config)) { var payload = testEventSender.RequirePayload(); Assert.Equal(EventDataKind.DiagnosticEvent, payload.Kind); Assert.Equal(1, payload.EventCount); var data = LdValue.Parse(payload.Data); Assert.Equal("diagnostic-init", data.Get("kind").AsString); AssertHelpers.JsonEqual(ExpectedPlatform(), data.Get("platform")); AssertHelpers.JsonEqual(expectedSdk, data.Get("sdk")); Assert.Equal("DK_KEY", data.Get("id").Get("sdkKeySuffix").AsString); var timestamp = data.Get("creationDate").AsLong; Assert.NotEqual(0, timestamp); } }
private void TestDiagnosticConfig( Func <ConfigurationBuilder, ConfigurationBuilder> modConfig, Func <EventProcessorBuilder, EventProcessorBuilder> modEvents, LdValue.ObjectBuilder expected ) { var eventsBuilder = Components.SendEvents() .EventSender(testEventSender); modEvents?.Invoke(eventsBuilder); var configBuilder = Configuration.Builder(sdkKey) .Events(eventsBuilder) .Http(Components.HttpConfiguration().MessageHandler(new StubMessageHandler(HttpStatusCode.Unauthorized))) .Logging(Components.Logging(testLogging)) .StartWaitTime(testStartWaitTime); modConfig?.Invoke(configBuilder); using (var client = new LdClient(configBuilder.Build())) { var payload = testEventSender.RequirePayload(); Assert.Equal(EventDataKind.DiagnosticEvent, payload.Kind); Assert.Equal(1, payload.EventCount); var data = LdValue.Parse(payload.Data); Assert.Equal("diagnostic-init", data.Get("kind").AsString); AssertHelpers.JsonEqual(expected.Build(), data.Get("configuration")); } }
public void CustomConfigForEvents() { TestDiagnosticConfig( c => c.Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyStreamingResponse())), e => e.AllAttributesPrivate(true) .BaseUri(new Uri("http://custom")) .Capacity(333) .DiagnosticRecordingInterval(TimeSpan.FromMinutes(32)) .FlushInterval(TimeSpan.FromMilliseconds(555)) .InlineUsersInEvents(true) .UserKeysCapacity(444) .UserKeysFlushInterval(TimeSpan.FromMinutes(23)), ExpectedConfigProps.Base() .WithStoreDefaults() .WithStreamingDefaults() .Add("allAttributesPrivate", true) .Add("customEventsURI", true) .Add("diagnosticRecordingIntervalMillis", TimeSpan.FromMinutes(32).TotalMilliseconds) .Add("eventsCapacity", 333) .Add("eventsFlushIntervalMillis", 555) .Add("inlineUsersInEvents", true) .Add("samplingInterval", 0) // obsolete, no way to set this .Add("userKeysCapacity", 444) .Add("userKeysFlushIntervalMillis", TimeSpan.FromMinutes(23).TotalMilliseconds) ); }
public void ConfigDefaults() { // Note that in all of the test configurations where the streaming or polling data source // is enabled, we're setting a fake HTTP message handler so it doesn't try to do any real // HTTP requests that would fail and (depending on timing) disrupt the test. TestDiagnosticConfig( c => c.Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyStreamingResponse())), null, ExpectedConfigProps.Base() ); }
public void DefaultEventsBaseUri() { using (var client = new LdClient( BasicConfig() .Events(Components.SendEvents()) .Http(Components.HttpConfiguration().MessageHandler(_stubHandler)) .Build())) { var req = _stubHandler.Requests.ExpectValue(); Assert.Equal(StandardEndpoints.DefaultEventsBaseUri, BaseUriOf(req.RequestUri)); } }
public void CustomConfigForStreaming() { TestDiagnosticConfig( c => c.DataSource( Components.StreamingDataSource() .InitialReconnectDelay(TimeSpan.FromSeconds(2)) ) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyStreamingResponse())), null, ExpectedConfigProps.Base() .Set("reconnectTimeMillis", 2000) ); }
public void CustomConfigForHTTP() { TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .ConnectTimeout(TimeSpan.FromMilliseconds(8888)) .ReadTimeout(TimeSpan.FromMilliseconds(9999)) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ), null, ExpectedConfigProps.Base() .Set("connectTimeoutMillis", 8888) .Set("socketTimeoutMillis", 9999) .Set("usingProxy", false) .Set("usingProxyAuthenticator", false) ); var proxyUri = new Uri("http://fake"); var proxy = new WebProxy(proxyUri); TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .Proxy(proxy) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ), null, ExpectedConfigProps.Base() .Set("usingProxy", true) ); var credentials = new CredentialCache(); credentials.Add(proxyUri, "Basic", new NetworkCredential("user", "pass")); var proxyWithAuth = new WebProxy(proxyUri); proxyWithAuth.Credentials = credentials; TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .Proxy(proxyWithAuth) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ), null, ExpectedConfigProps.Base() .Set("usingProxy", true) .Set("usingProxyAuthenticator", true) ); }
public void CustomEventsBaseUriWithDeprecatedMethod() { using (var client = new LdClient( BasicConfig() .Events(Components.SendEvents().BaseUri(CustomUri)) .Http(Components.HttpConfiguration().MessageHandler(_stubHandler)) .Build())) { var req = _stubHandler.Requests.ExpectValue(); Assert.Equal(CustomUri, BaseUriOf(req.RequestUri)); AssertLogMessageRegex(false, LogLevel.Error, "You have set custom ServiceEndpoints without specifying"); } }
public void CustomPollingDataSourceBaseUri() { using (var client = new LdClient( BasicConfig() .DataSource(Components.PollingDataSource()) .Http(Components.HttpConfiguration().MessageHandler(_stubHandler)) .ServiceEndpoints(Components.ServiceEndpoints().Polling(CustomUri)) .Build())) { var req = _stubHandler.Requests.ExpectValue(); Assert.Equal(CustomUri, BaseUriOf(req.RequestUri)); Assert.False(LogCapture.HasMessageWithRegex(LogLevel.Error, "You have set custom ServiceEndpoints without specifying")); } }
static void TestHttpClientCanUseProxy(Handler responseHandler, HttpConfigurationTestAction testActionShouldSucceed) { // To verify that a web proxy will really be used if provided, we set up a proxy // configuration pointing to our test server. It's not really a proxy server, // but if it receives a request that was intended for some other URI (instead of // the SDK trying to access that other URI directly), then that's a success. using (var server = HttpServer.Start(responseHandler)) { var proxy = new WebProxy(server.Uri); var httpConfig = Components.HttpConfiguration().Proxy(proxy); var fakeBaseUri = new Uri("http://not-a-real-host"); testActionShouldSucceed(fakeBaseUri, httpConfig, server); } }
public void ErrorIsLoggedIfANecessaryUriIsNotSetWhenOtherCustomUrisAreSet() { var logCapture1 = Logs.Capture(); using (var client = new LdClient( BasicConfig() .DataSource(Components.StreamingDataSource()) .Http(Components.HttpConfiguration().MessageHandler(_stubHandler)) .Logging(logCapture1) .ServiceEndpoints(Components.ServiceEndpoints().Polling(CustomUri)) .Build())) { Assert.True(logCapture1.HasMessageWithRegex(LogLevel.Error, "You have set custom ServiceEndpoints without specifying the Streaming base URI")); } var logCapture2 = Logs.Capture(); using (var client = new LdClient( BasicConfig() .DataSource(Components.PollingDataSource()) .Http(Components.HttpConfiguration().MessageHandler(_stubHandler)) .Logging(logCapture2) .ServiceEndpoints(Components.ServiceEndpoints().Events(CustomUri)) .Build())) { Assert.True(logCapture2.HasMessageWithRegex(LogLevel.Error, "You have set custom ServiceEndpoints without specifying the Polling base URI")); } var logCapture3 = Logs.Capture(); using (var client = new LdClient( BasicConfig() .Events(Components.SendEvents()) .Http(Components.HttpConfiguration().MessageHandler(_stubHandler)) .Logging(logCapture3) .ServiceEndpoints(Components.ServiceEndpoints().Streaming(CustomUri)) .Build())) { Assert.True(logCapture3.HasMessageWithRegex(LogLevel.Error, "You have set custom ServiceEndpoints without specifying the Events base URI")); } }
public void CustomConfigForPolling() { TestDiagnosticConfig( c => c.DataSource(Components.PollingDataSource()) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyPollingResponse())), null, ExpectedConfigProps.Base() .WithPollingDefaults() ); TestDiagnosticConfig( c => c.DataSource( Components.PollingDataSource() .PollInterval(TimeSpan.FromSeconds(45)) ) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyPollingResponse())), null, ExpectedConfigProps.Base() .WithPollingDefaults() .Set("pollingIntervalMillis", 45000) ); }
static void TestHttpClientCanUseCustomMessageHandler(Handler responseHandler, HttpConfigurationTestAction testActionShouldSucceed) { // To verify that a custom HttpMessageHandler will really be used if provided, we // create one that behaves normally except that it modifies the request path. // Then we verify that the server received a request with a modified path. var recordAndDelegate = Handlers.Record(out var recorder).Then(responseHandler); using (var server = HttpServer.Start(recordAndDelegate)) { var suffix = "/modified-by-test"; var messageHandler = new MessageHandlerThatAddsPathSuffix(suffix); var httpConfig = Components.HttpConfiguration().MessageHandler(messageHandler); testActionShouldSucceed(server.Uri, httpConfig, server); var request = recorder.RequireRequest(); Assert.EndsWith(suffix, request.Path); recorder.RequireNoRequests(TimeSpan.FromMilliseconds(100)); } }
public void CustomConfigGeneralProperties() { TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .ConnectTimeout(TimeSpan.FromMilliseconds(1001)) .ReadTimeout(TimeSpan.FromMilliseconds(1003)) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ) .StartWaitTime(TimeSpan.FromMilliseconds(2)), null, LdValue.BuildObject() .WithStoreDefaults() .WithEventsDefaults() .WithStreamingDefaults() .Add("connectTimeoutMillis", 1001) .Add("socketTimeoutMillis", 1003) .Add("startWaitMillis", 2) .Add("usingProxy", false) .Add("usingProxyAuthenticator", false) ); }
public void CustomConfigForPolling() { TestDiagnosticConfig( c => c.DataSource( Components.PollingDataSource() .PollInterval(TimeSpan.FromSeconds(45)) ) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyPollingResponse())), null, ExpectedConfigProps.Base() .WithStoreDefaults() .WithEventsDefaults() .Add("customBaseURI", false) .Add("customStreamURI", false) .Add("pollingIntervalMillis", 45000) .Add("streamingDisabled", true) .Add("usingRelayDaemon", false) ); TestDiagnosticConfig( c => c.DataSource( Components.PollingDataSource() .BaseUri(new Uri("http://custom")) .PollInterval(TimeSpan.FromSeconds(45)) ) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyPollingResponse())), null, ExpectedConfigProps.Base() .WithStoreDefaults() .WithEventsDefaults() .Add("customBaseURI", true) .Add("customStreamURI", false) .Add("pollingIntervalMillis", 45000) .Add("streamingDisabled", true) .Add("usingRelayDaemon", false) ); }
public void CustomConfigForHTTP() { TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .ConnectTimeout(TimeSpan.FromMilliseconds(8888)) .ReadTimeout(TimeSpan.FromMilliseconds(9999)) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ), null, LdValue.BuildObject() .Add("connectTimeoutMillis", 8888) .Add("socketTimeoutMillis", 9999) .Add("startWaitMillis", LdClientDiagnosticEventTest.testStartWaitTime.TotalMilliseconds) .Add("usingProxy", false) .Add("usingProxyAuthenticator", false) .WithStoreDefaults() .WithStreamingDefaults() .WithEventsDefaults() ); var proxyUri = new Uri("http://fake"); var proxy = new WebProxy(proxyUri); TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .Proxy(proxy) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ), null, LdValue.BuildObject() .Add("connectTimeoutMillis", HttpConfigurationBuilder.DefaultConnectTimeout.TotalMilliseconds) .Add("socketTimeoutMillis", HttpConfigurationBuilder.DefaultReadTimeout.TotalMilliseconds) .Add("startWaitMillis", LdClientDiagnosticEventTest.testStartWaitTime.TotalMilliseconds) .Add("usingProxy", true) .Add("usingProxyAuthenticator", false) .WithStoreDefaults() .WithStreamingDefaults() .WithEventsDefaults() ); var credentials = new CredentialCache(); credentials.Add(proxyUri, "Basic", new NetworkCredential("user", "pass")); var proxyWithAuth = new WebProxy(proxyUri); proxyWithAuth.Credentials = credentials; TestDiagnosticConfig( c => c.Http( Components.HttpConfiguration() .Proxy(proxyWithAuth) .MessageHandler(StubMessageHandler.EmptyStreamingResponse()) ), null, LdValue.BuildObject() .Add("connectTimeoutMillis", HttpConfigurationBuilder.DefaultConnectTimeout.TotalMilliseconds) .Add("socketTimeoutMillis", HttpConfigurationBuilder.DefaultReadTimeout.TotalMilliseconds) .Add("startWaitMillis", LdClientDiagnosticEventTest.testStartWaitTime.TotalMilliseconds) .Add("usingProxy", true) .Add("usingProxyAuthenticator", true) .WithStoreDefaults() .WithStreamingDefaults() .WithEventsDefaults() ); }
/// <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. } }
public void TestConfigForServiceEndpoints() { TestDiagnosticConfig( c => c.ServiceEndpoints(Components.ServiceEndpoints().RelayProxy("http://custom")) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyStreamingResponse())), null, ExpectedConfigProps.Base() .Set("customBaseURI", false) // this is the polling base URI, not relevant in streaming mode .Set("customStreamURI", true) .Set("customEventsURI", true) ); TestDiagnosticConfig( c => c.ServiceEndpoints(Components.ServiceEndpoints().RelayProxy("http://custom")) .DataSource(Components.PollingDataSource()) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyPollingResponse())), null, ExpectedConfigProps.Base() .WithPollingDefaults() .Set("customBaseURI", true) .Set("customEventsURI", true) ); TestDiagnosticConfig( c => c.ServiceEndpoints(Components.ServiceEndpoints() .Streaming("http://custom-streaming") .Polling("http://custom-polling") .Events("http://custom-events")) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyStreamingResponse())), null, ExpectedConfigProps.Base() .Set("customBaseURI", false) // this is the polling base URI, not relevant in streaming mode .Set("customStreamURI", true) .Set("customEventsURI", true) ); TestDiagnosticConfig( c => c.DataSource( #pragma warning disable CS0618 // using deprecated symbol Components.StreamingDataSource() .BaseUri(new Uri("http://custom")) #pragma warning restore CS0618 ) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyStreamingResponse())), null, ExpectedConfigProps.Base() .Set("customStreamURI", true) ); TestDiagnosticConfig( c => c.DataSource( #pragma warning disable CS0618 // using deprecated symbol Components.PollingDataSource().BaseUri(new Uri("http://custom")) #pragma warning restore CS0618 ) .Http(Components.HttpConfiguration().MessageHandler(StubMessageHandler.EmptyPollingResponse())), null, ExpectedConfigProps.Base() .WithPollingDefaults() .Set("customBaseURI", true) ); }