public UnleashServices(UnleashSettings settings, IRandom random, IUnleashApiClientFactory unleashApiClientFactory,
                               IUnleashScheduledTaskManager scheduledTaskManager, IToggleCollectionCache toggleCollectionCache,
                               IEnumerable <IStrategy> strategies)
        {
            this.Random = random ?? throw new ArgumentNullException(nameof(random));

            this.scheduledTaskManager = scheduledTaskManager ?? throw new ArgumentNullException(nameof(scheduledTaskManager));

            var settingsValidator = new UnleashSettingsValidator();

            settingsValidator.Validate(settings);

            StrategyMap = BuildStrategyMap(strategies?.ToArray() ?? new IStrategy[0]);

            CancellationToken = cancellationTokenSource.Token;

            var cachedFilesResult = toggleCollectionCache.Load(cancellationTokenSource.Token).GetAwaiter().GetResult();

            cacheMiss = cachedFilesResult.IsCacheMiss;


            ToggleCollection = new ThreadSafeToggleCollection
            {
                Instance = cachedFilesResult.InitialToggleCollection ?? new ToggleCollection()
            };

            MetricsBucket = new ThreadSafeMetricsBucket();

            var scheduledTasks = CreateScheduledTasks(settings, unleashApiClientFactory, toggleCollectionCache, cachedFilesResult);

            scheduledTaskManager.Configure(scheduledTasks, CancellationToken);
        }
        public UnleashServiceFixture()
        {
            Settings = new UnleashSettings
            {
                UnleashApi  = new Uri("http://localhost:4242/"),
                AppName     = "IntegrationTest",
                InstanceTag = "Test"
            };

            UnleashServices = new DefaultUnleashServices(Settings);
            ContextProvider = new DefaultUnleashContextProvider();
            Unleash         = new Unleash(Settings, UnleashServices, ContextProvider);

            UnleashServices?.FeatureToggleLoadComplete(false, CancellationToken.None).Wait();

            var httpClient = new HttpClient
            {
                BaseAddress = new Uri("http://localhost:4242/admin/")
            };

            httpClient.DefaultRequestHeaders.ConnectionClose = false;
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json");
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
            httpClient.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue {
                NoCache = true
            };

            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();

            JsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings);
            AdminApiClient = new UnleashAdminApiClient(httpClient, JsonSerializer);
        }
Esempio n. 3
0
        internal async Task ExecuteAsync_WhenApiReturns200Ok_CompletesSuccessfully(
            [Frozen] UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] Mock <IUnleashApiClientFactory> apiClientFactoryMock,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            [Frozen] MetricsBucket metricsBucket)
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            var threadSafeMetricsBucket = new ThreadSafeMetricsBucket(metricsBucket);
            var backgroundTask          = new ClientMetricsBackgroundTask(apiClientFactoryMock.Object, settings, threadSafeMetricsBucket);

            httpMessageHandler.SetupPostSendMetricsRequestForSuccess(requestHeaders);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            apiClientFactoryMock.Setup(cf => cf.CreateClient()).Returns(apiClient);

            await backgroundTask.ExecuteAsync(CancellationToken.None);

            httpMessageHandler.VerifyAll();
            apiClientFactoryMock.VerifyAll();
        }
Esempio n. 4
0
        internal async Task FetchToggles_WhenServerReturns304NotModified_ReturnsCacheHitResult(
            UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            string etagMinusQuotes
            )
        {
            var etag = $"\"{etagMinusQuotes}\"";

            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            httpMessageHandler.SetupGetFeaturesRequestForCacheHit(requestHeaders, etag);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            var actualFetchTogglesResult = await apiClient.FetchToggles(etag, CancellationToken.None);

            Assert.Null(actualFetchTogglesResult.ToggleCollection);
            Assert.False(actualFetchTogglesResult.HasChanged);
            Assert.Equal(etag, actualFetchTogglesResult.Etag);

            httpMessageHandler.VerifyAll();
        }
Esempio n. 5
0
        internal async Task ExecuteAsync_WhenHttpExceptionOccurs_CompletesSuccessfully(
            HttpStatusCode statusCode,
            string responseBody,
            string responseContentType,
            [Frozen] UnleashSettings settings,
            [Frozen] ThreadSafeToggleCollection toggleCollection,
            [Frozen] Mock <IToggleCollectionCache> toggleCollectionCache,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] Mock <IUnleashApiClientFactory> apiClientFactoryMock,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            TaskCompletionSource <object> taskCompletionSource)
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            var backgroundTask = new FetchFeatureTogglesTask(apiClientFactoryMock.Object, toggleCollection, toggleCollectionCache.Object, taskCompletionSource);

            httpMessageHandler.SetupGetFeaturesRequestForException(requestHeaders, statusCode, responseBody, responseContentType);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            apiClientFactoryMock.Setup(cf => cf.CreateClient()).Returns(apiClient);

            await backgroundTask.ExecuteAsync(CancellationToken.None);

            Assert.True(taskCompletionSource.Task.IsCompletedSuccessfully);

            httpMessageHandler.VerifyAll();
            apiClientFactoryMock.VerifyAll();
            toggleCollectionCache.VerifyNoOtherCalls();
        }
Esempio n. 6
0
        internal async Task FetchToggles_WhenHttpExceptionOccurs_ReturnsEmptyResult(
            HttpStatusCode responseStatusCode,
            string responseBody,
            string responseContentType,
            UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            string etag
            )
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            httpMessageHandler.SetupGetFeaturesRequestForException(requestHeaders, responseStatusCode, responseBody, responseContentType);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            var actualFetchTogglesResult = await apiClient.FetchToggles(etag, CancellationToken.None);

            Assert.Null(actualFetchTogglesResult.ToggleCollection);
            Assert.Null(actualFetchTogglesResult.Etag);
            Assert.False(actualFetchTogglesResult.HasChanged);

            httpMessageHandler.VerifyAll();
        }
Esempio n. 7
0
        internal async Task FetchToggles_WhenServerReturnsExpectedToggles_ReturnsValidResult(
            UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            string etag
            )
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            var expectedToggles = new ToggleCollection();

            httpMessageHandler.SetupGetFeaturesRequestForSuccess(jsonSerializer, expectedToggles, requestHeaders);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            var actualFetchTogglesResult = await apiClient.FetchToggles(etag, CancellationToken.None);

            var actualToggles = actualFetchTogglesResult.ToggleCollection;

            Assert.Equal(expectedToggles.Features, actualToggles.Features);
            Assert.True(actualFetchTogglesResult.HasChanged);
            Assert.NotEqual(etag, actualFetchTogglesResult.Etag);

            httpMessageHandler.VerifyAll();
        }
Esempio n. 8
0
        internal async Task RegisterMetrics_WhenHttpExceptionOccurs_ReturnsFalse(
            HttpStatusCode responseStatusCode,
            string responseBody,
            string responseContentType,
            UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            MetricsBucket metricsBucket
            )
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            httpMessageHandler.SetupPostSendMetricsRequestForException(requestHeaders, responseStatusCode, responseBody, responseContentType);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            var threadSafeMetricsBucket = new ThreadSafeMetricsBucket(metricsBucket);
            var successResult           = await apiClient.SendMetrics(threadSafeMetricsBucket, CancellationToken.None);

            Assert.False(successResult);

            httpMessageHandler.VerifyAll();
        }
        public async Task Load_WhenTogglesOrEtagFileDoesNotExists_ReturnsEmptyResult(
            bool toggleFileExists,
            bool etagFileExists,
            [Frozen] UnleashSettings settings,
            [Frozen] Mock <IFileSystem> fileSystem,
            FileSystemToggleCollectionCache cache
            )
        {
            var etagFilePath   = settings.GetFeatureToggleETagFilePath();
            var toggleFilePath = settings.GetFeatureToggleFilePath();

            fileSystem.Setup(fs => fs.FileExists(etagFilePath)).Returns(etagFileExists);

            if (etagFileExists)
            {
                fileSystem.Setup(fs => fs.FileExists(toggleFilePath)).Returns(toggleFileExists);
            }

            var result = await cache.Load(CancellationToken.None);

            Assert.Equal(string.Empty, result.InitialETag);
            Assert.Null(result.InitialToggleCollection);

            fileSystem.VerifyAll();
        }
Esempio n. 10
0
        internal async Task RegisterMetrics_WhenServerReturns200Ok_ReturnsTrue(
            UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            MetricsBucket metricsBucket
            )
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            httpMessageHandler.SetupPostSendMetricsRequestForSuccess(requestHeaders);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            var threadSafeMetricsBucket = new ThreadSafeMetricsBucket(metricsBucket);
            var successResult           = await apiClient.SendMetrics(threadSafeMetricsBucket, CancellationToken.None);

            Assert.True(successResult);

            httpMessageHandler.VerifyAll();
        }
Esempio n. 11
0
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            var form = new UnleashForm();

            JsonSerializerTester.Assert(new NewtonsoftJson7Serializer());

            settings = new UnleashSettings
            {
                UnleashApi = new Uri("http://unleash.herokuapp.com/"),
                //UnleashApi = new Uri("http://localhost:4242/"),
                AppName                = "dotnet-forms-test",
                InstanceTag            = "instance 1",
                SendMetricsInterval    = TimeSpan.FromSeconds(5),
                FetchTogglesInterval   = TimeSpan.FromSeconds(10),
                UnleashContextProvider = new WinFormsContextProvider(form),
                JsonSerializer         = new NewtonsoftJson7Serializer()
            };

            unleash       = new DefaultUnleash(settings);
            form.Unleash  = unleash;
            form.Settings = settings;

            Application.ApplicationExit += (sender, args) =>
            {
                unleash?.Dispose();
            };

            Application.Run(form);
        }
        public async Task Load_WhenValidToggleAndEtagFilesExist_ReturnsExpectedResult(
            [Frozen] UnleashSettings settings,
            [Frozen] Mock <IFileSystem> fileSystem,
            [Frozen] Mock <IJsonSerializer> jsonSerializer,
            FileSystemToggleCollectionCache cache,
            ToggleCollection toggleCollection,
            string etag
            )
        {
            var toggleFilePath = settings.GetFeatureToggleFilePath();
            var etagFilePath   = settings.GetFeatureToggleETagFilePath();

            fileSystem.Setup(fs => fs.FileExists(toggleFilePath)).Returns(true);
            fileSystem.Setup(fs => fs.FileExists(etagFilePath)).Returns(true);

            var ms = new MemoryStream();

            fileSystem.Setup(fs => fs.FileOpenRead(toggleFilePath)).Returns(ms);
            fileSystem.Setup(fs => fs.ReadAllText(etagFilePath)).Returns(etag);

            jsonSerializer.Setup(js => js.Deserialize <ToggleCollection>(ms)).Returns(toggleCollection);

            var result = await cache.Load(CancellationToken.None);

            Assert.Equal(etag, result.InitialETag);
            Assert.Same(toggleCollection, result.InitialToggleCollection);

            fileSystem.VerifyAll();
            jsonSerializer.VerifyAll();
        }
Esempio n. 13
0
        internal async Task ExecuteAsync_WhenHttpExceptionOccurs_CompletesSuccessfully(
            HttpStatusCode statusCode,
            string responseBody,
            string responseContentType,
            [Frozen] UnleashSettings settings,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] Mock <IUnleashApiClientFactory> apiClientFactoryMock,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            List <string> strategies)
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            var backgroundTask = new ClientRegistrationBackgroundTask(apiClientFactoryMock.Object, settings, strategies);

            httpMessageHandler.SetupPostRegisterClientRequestForException(requestHeaders, statusCode, responseBody, responseContentType);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            apiClientFactoryMock.Setup(cf => cf.CreateClient()).Returns(apiClient);

            await backgroundTask.ExecuteAsync(CancellationToken.None);

            httpMessageHandler.VerifyAll();
            apiClientFactoryMock.VerifyAll();
        }
Esempio n. 14
0
 public FileSystemToggleCollectionCache(UnleashSettings settings, IJsonSerializer jsonSerializer, IFileSystem fileSystem)
 {
     this.jsonSerializer = jsonSerializer;
     this.fileSystem     = fileSystem;
     this.toggleFile     = settings.GetFeatureToggleFilePath();
     this.etagFile       = settings.GetFeatureToggleETagFilePath();
 }
 public DefaultUnleashApiClientFactory(UnleashSettings settings, IHttpClientFactory httpClientFactory,
                                       IJsonSerializer jsonSerializer, UnleashApiClientRequestHeaders unleashApiClientRequestHeaders)
 {
     this.settings          = settings;
     this.httpClientFactory = httpClientFactory;
     this.jsonSerializer    = jsonSerializer;
     this.unleashApiClientRequestHeaders = unleashApiClientRequestHeaders;
 }
Esempio n. 16
0
        public void Should_set_environment_to_default()
        {
            // Act
            var settings = new UnleashSettings();

            // Assert
            settings.Environment.Should().Be("default");
        }
 public ClientMetricsBackgroundTask(
     IUnleashApiClient apiClient,
     UnleashSettings settings,
     ThreadSafeMetricsBucket metricsBucket)
 {
     this.apiClient     = apiClient;
     this.settings      = settings;
     this.metricsBucket = metricsBucket;
 }
Esempio n. 18
0
 public ClientRegistrationBackgroundTask(
     IUnleashApiClientFactory apiClientFactory,
     UnleashSettings settings,
     List <string> strategies)
 {
     this.apiClientFactory = apiClientFactory;
     this.settings         = settings;
     this.strategies       = strategies;
 }
Esempio n. 19
0
        public static IUnleash CreateUnleash(TestDefinition testDefinition, UnleashContextDefinition contextDefinition)
        {
            var fakeHttpClientFactory  = A.Fake <IHttpClientFactory>();
            var fakeHttpMessageHandler = new TestHttpMessageHandler();
            var httpClient             = new HttpClient(fakeHttpMessageHandler)
            {
                BaseAddress = new Uri("http://localhost")
            };
            var fakeScheduler  = A.Fake <IUnleashScheduledTaskManager>();
            var fakeFileSystem = new MockFileSystem();

            A.CallTo(() => fakeHttpClientFactory.Create(A <Uri> ._)).Returns(httpClient);
            A.CallTo(() => fakeScheduler.Configure(A <IEnumerable <IUnleashScheduledTask> > ._, A <CancellationToken> ._)).Invokes(action =>
            {
                var task = ((IEnumerable <IUnleashScheduledTask>)action.Arguments[0]).First();
                task.ExecuteAsync((CancellationToken)action.Arguments[1]).Wait();
            });

            fakeHttpMessageHandler.Response = new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content    = new StringContent(testDefinition.State.ToString(), Encoding.UTF8, "application/json"),
                Headers    =
                {
                    ETag = new EntityTagHeaderValue("\"123\"")
                }
            };

            var contextBuilder = new UnleashContext.Builder()
                                 .UserId(contextDefinition.UserId)
                                 .SessionId(contextDefinition.SessionId)
                                 .RemoteAddress(contextDefinition.RemoteAddress)
                                 .Environment(contextDefinition.Environment)
                                 .AppName(contextDefinition.AppName);

            if (contextDefinition.Properties != null)
            {
                foreach (var property in contextDefinition.Properties)
                {
                    contextBuilder.AddProperty(property.Key, property.Value);
                }
            }

            var settings = new UnleashSettings
            {
                AppName = testDefinition.Name,
                UnleashContextProvider = new DefaultUnleashContextProvider(contextBuilder.Build()),
                HttpClientFactory      = fakeHttpClientFactory,
                ScheduledTaskManager   = fakeScheduler,
                FileSystem             = fakeFileSystem
            };

            var unleash = new DefaultUnleash(settings);

            return(unleash);
        }
        ///// <summary>
        ///// Initializes a new instance of Unleash client.
        ///// </summary>
        ///// <param name="SynchronousInitialization">If true, fetch and cache toggles before returning. If false, allow the unleash client schedule an initial poll of features in the background</param>
        public async Task <IUnleash> Generate(UnleashSettings settings, bool SynchronousInitialization = false)
        {
            if (SynchronousInitialization)
            {
                settings.ScheduleFeatureToggleFetchImmediatly = false;
                var unleash = new DefaultUnleash(settings);
                await unleash.services.FetchFeatureTogglesTask.ExecuteAsync(CancellationToken.None);

                return(unleash);
            }
            return(new DefaultUnleash(settings));
        }
        public static IServiceCollection AddUnleash(this IServiceCollection serviceCollection, Action <UnleashSettings> configurator)
        {
            // This is to support the anonymous serviceCollection.AddSingleton<IUnleash, DefaultUnleash>() below.  If
            // DefaultUnleash's constructor asked for an IEnumerable<IStrategy> instead of an IStrategy[] this wouldn't
            // be necessary.  It shouldn't be a breaking change given that T[] : IEnumerable<T>.
            serviceCollection.AddSingleton(sp => sp.GetRequiredService <IEnumerable <IStrategy> >().ToArray());

            // ASP.NET Core will create a scope per HTTP request, message queue consumer code will typically create a
            // scope per message, timer-based services will create a scope per interval.   Disposing the scope disposes
            // the IDisposable scopes resolved.  We'd like to rely on DI's scope to provide isolation across
            // requests/messages/intervals, basically just new-ing up a Dictionary<string,string>() per request

            // In your docs, you say "If you are using Asp.Net the UnleashContextProvider will typically be a 'request
            // scoped' instance.".  I agree that makes sense here, and am trying to use DI to enforce it/handle the one
            // state per scope problem.  Also, my goal is for this extension method to work in anything that uses the
            // DI Scope pattern w/o any changes.
            serviceCollection.AddScoped <IUnleashContextProvider, ScopedDictionaryContextProvider>();

            // Since IUnleash should be a singleton, UnleashSettings must be as well.  However, the
            // UnleashContextProvider property is scoped.
            serviceCollection.AddSingleton <UnleashSettings>(sp =>
            {
                // In order to configure this, we are basically capturing a scoped dependency as a singleton.  This
                // instance will never exist within a scope and so it won't have anything to capture.

                var contextProvider = sp.GetRequiredService <IUnleashContextProvider>(); // Crash happens here

                var settings = new UnleashSettings
                {
                    UnleashContextProvider = contextProvider
                };

                configurator?.Invoke(settings);

                return(settings);
            });

            serviceCollection.AddSingleton <IUnleash, DefaultUnleash>();

            /*
             * Should be equivalent to:
             *
             * serviceCollection.AddSingleton<IUnleash>(sp =>
             * {
             *  var unleashSettings = sp.GetRequiredService<UnleashSettings>();
             *  var strategies = sp.GetRequiredService<IEnumerable<IStrategy>>().ToArray();
             *
             *  return new DefaultUnleash(unleashSettings, strategies);
             * });
             */

            return(serviceCollection);
        }
Esempio n. 22
0
        /// <summary>
        /// Initializes a new instance of Unleash client.
        /// </summary>
        /// <param name="synchronousInitialization">If true, fetch and cache toggles before returning. If false, allow the unleash client schedule an initial poll of features in the background</param>
        /// <param name="strategies">Custom strategies, added in addtion to builtIn strategies.</param>
        public async Task <IUnleash> CreateClientAsync(UnleashSettings settings, bool synchronousInitialization = false, params IStrategy[] strategies)
        {
            if (synchronousInitialization)
            {
                settings.ScheduleFeatureToggleFetchImmediatly = false;
                var unleash = new DefaultUnleash(settings, strategies);
                await unleash.services.FetchFeatureTogglesTask.ExecuteAsync(CancellationToken.None).ConfigureAwait(false);

                return(unleash);
            }
            return(new DefaultUnleash(settings, strategies));
        }
Esempio n. 23
0
        internal async Task ExecuteAsync_WhenApiReturns200Ok_CompletesSuccessfully(
            [Frozen] UnleashSettings settings,
            [Frozen] ThreadSafeToggleCollection toggleCollection,
            [Frozen] Mock <IToggleCollectionCache> toggleCollectionCache,
            [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler,
            [Frozen] Mock <IUnleashApiClientFactory> apiClientFactoryMock,
            [Frozen] UnleashApiClientRequestHeaders requestHeaders,
            TaskCompletionSource <object> taskCompletionSource)
        {
            var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings();
            var jsonSerializer         = new NewtonsoftJsonSerializer(jsonSerializerSettings);

            var toggleCollectionInstance = toggleCollection.Instance;

            toggleCollectionCache
            .Setup(
                x => x.Save(
                    It.Is <ToggleCollection>(
                        y => y.Version.Equals(toggleCollectionInstance.Version) &&
                        y.Features.All(
                            z => toggleCollectionInstance.Features.Any(zz => zz.Name.Equals(z.Name))
                            )
                        ),
                    It.IsAny <string>(),
                    CancellationToken.None
                    )
                )
            .Returns(Task.CompletedTask);

            var backgroundTask = new FetchFeatureTogglesTask(apiClientFactoryMock.Object, toggleCollection, toggleCollectionCache.Object, taskCompletionSource);

            httpMessageHandler.SetupGetFeaturesRequestForSuccess(jsonSerializer, toggleCollectionInstance, requestHeaders);

            var httpClient = new HttpClient(httpMessageHandler.Object)
            {
                BaseAddress = settings.UnleashApi
            };
            var apiClient = new UnleashApiClient(httpClient, jsonSerializer, requestHeaders);

            apiClientFactoryMock.Setup(cf => cf.CreateClient()).Returns(apiClient);

            await backgroundTask.ExecuteAsync(CancellationToken.None);

            Assert.True(taskCompletionSource.Task.IsCompletedSuccessfully);

            httpMessageHandler.VerifyAll();
            apiClientFactoryMock.VerifyAll();
            toggleCollectionCache.VerifyAll();
        }
Esempio n. 24
0
        /// <summary>
        /// Initializes a new instance of Unleash client.
        /// </summary>
        /// <param name="synchronousInitialization">If true, fetch and cache toggles before returning. If false, allow the unleash client schedule an initial poll of features in the background</param>
        /// <param name="strategies">Custom strategies, added in addtion to builtIn strategies.</param>
        public IUnleash CreateClient(UnleashSettings settings, bool synchronousInitialization = false, params IStrategy[] strategies)
        {
            if (synchronousInitialization)
            {
                settings.ScheduleFeatureToggleFetchImmediatly = false;
                var unleash = new DefaultUnleash(settings, strategies);
                TaskFactory
                .StartNew(() => unleash.services.FetchFeatureTogglesTask.ExecuteAsync(CancellationToken.None))
                .Unwrap()
                .GetAwaiter()
                .GetResult();

                return(unleash);
            }
            return(new DefaultUnleash(settings, strategies));
        }
Esempio n. 25
0
        public void Validate(UnleashSettings settings)
        {
            if (settings.UnleashApi == null)
            {
                throw new UnleashException("You are required to specify an uri to an unleash service");
            }

            if (settings.AppName == null)
            {
                throw new UnleashException("You are required to specify an appName");
            }

            if (settings.InstanceTag == null)
            {
                throw new UnleashException("You are required to specify an instance id");
            }
        }
Esempio n. 26
0
 public DefaultUnleashServices(UnleashSettings settings)
 {
     _services = new UnleashServices(
         settings,
         DefaultRandom,
         new DefaultUnleashApiClientFactory(
             settings,
             DefaultHttpClientFactory,
             DefaultJsonSerializer,
             new UnleashApiClientRequestHeaders
     {
         AppName           = settings.AppName,
         CustomHttpHeaders = settings.CustomHttpHeaders,
         InstanceTag       = settings.InstanceTag
     }),
         ScheduledTaskManager,
         new FileSystemToggleCollectionCache(
             settings,
             DefaultJsonSerializer,
             new FileSystem()),
         DefaultStrategies);
 }
        private IEnumerable <IUnleashScheduledTask> CreateScheduledTasks(UnleashSettings settings,
                                                                         IUnleashApiClientFactory unleashApiClientFactory, IToggleCollectionCache toggleCollectionCache,
                                                                         ToggleCollectionCacheResult toggleCollectionCacheResult)
        {
            yield return(new FetchFeatureTogglesTask(
                             unleashApiClientFactory,
                             ToggleCollection,
                             toggleCollectionCache,
                             flagsFetchedFromUnleashTaskCompletionSource)
            {
                ExecuteDuringStartup = true,
                Interval = settings.FetchTogglesInterval,
                Etag = toggleCollectionCacheResult.InitialETag
            });

            if (settings.RegisterClient)
            {
                yield return(new ClientRegistrationBackgroundTask(
                                 unleashApiClientFactory,
                                 settings,
                                 StrategyMap.Keys.ToList())
                {
                    Interval = TimeSpan.Zero,
                    ExecuteDuringStartup = true
                });
            }

            if (settings.SendMetricsInterval != null)
            {
                yield return(new ClientMetricsBackgroundTask(
                                 unleashApiClientFactory,
                                 settings,
                                 MetricsBucket)
                {
                    ExecuteDuringStartup = false,
                    Interval = settings.SendMetricsInterval.Value
                });
            }
        }
Esempio n. 28
0
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            UnleashSettings = new UnleashSettings()
            {
                UnleashApi = new Uri("http://unleash.herokuapp.com/api/"),
                //UnleashApi = new Uri("http://localhost:4242/api/"),
                AppName                = "dotnet-api-test",
                InstanceTag            = "instance 1",
                SendMetricsInterval    = TimeSpan.FromSeconds(20),
                UnleashContextProvider = new AspNetContextProvider(),
                //JsonSerializer = new JsonNetSerializer()
            };

            UnleashInfo = UnleashSettings.ToString();

            Unleash = new DefaultUnleash(UnleashSettings);
        }
        public void Validate(UnleashSettings settings)
        {
            if (settings.UnleashApi == null)
            {
                throw new UnleashException("You are required to specify an uri to an unleash service");
            }

            if (settings.AppName == null)
            {
                throw new UnleashException("You are required to specify an appName");
            }

            if (settings.InstanceTag == null)
            {
                throw new UnleashException("You are required to specify an instance id");
            }

            if (settings.JsonSerializer == null)
            {
                throw new UnleashException("You are required to specify an json serializer");
            }

            settings.JsonSerializer = DynamicJsonLibraryChooser.CheckIfJsonSerializerCanBeInitialized(settings.JsonSerializer);
        }
Esempio n. 30
0
        /// <summary>
        /// This pattern is not recommended.  You will miss out on the Unleash.Extensions.* capabilities.  You should
        /// consider using the Generic Host if possible or minimally introducing dependency injection.  See the other
        /// sample projects for examples.  This shows the bare functionality most closely resembling the original
        /// Unleash .NET client (pre-.NET Core)
        /// </summary>
        /// <param name="args"></param>
        static async Task Main(string[] args)
        {
            System.Console.WriteLine("Optional Arguments: [userId] [sessionId] [featureToggleName] [extraParamName extraParamValue]");

            var settings = new UnleashSettings
            {
                UnleashApi           = new Uri("http://localhost:4242/"),
                AppName              = "Sample.Console",
                InstanceTag          = "Test",
                FetchTogglesInterval = TimeSpan.FromSeconds(30),
                SendMetricsInterval  = TimeSpan.FromSeconds(1)
            };

            var unleashContext = new UnleashContext();

            using (var unleashServices = new DefaultUnleashServices(settings))
            {
                var unleashContextProvider = new DefaultUnleashContextProvider(unleashContext);
                var unleash = new Unleash.Unleash(settings, unleashServices, unleashContextProvider);

                System.Console.WriteLine("Waiting for initial feature toggle load to complete...");
                await unleashServices.FeatureToggleLoadComplete(false, CancellationToken.None);

                System.Console.WriteLine("Feature toggles loaded.");

                // Configure settings from args/defaults
                var userId            = args.Length > 0 ? args[0] : "1";
                var sessionId         = args.Length > 1 ? args[1] : "1";
                var featureToggleName = args.Length > 2 ? args[2] : "unleash.sample.test.flag";
                var extraParamName    = args.Length > 4 ? args[3] : null;
                var extraParamValue   = args.Length > 4 ? args[4] : null;

                // Initialize context
                unleashContextProvider.Context.RemoteAddress = GetIpAddress() ?? "127.0.0.1";
                unleashContextProvider.Context.UserId        = userId;
                unleashContextProvider.Context.SessionId     = sessionId;
                if (extraParamName != null && extraParamValue != null)
                {
                    unleashContextProvider.Context.Properties[extraParamName] = extraParamValue;
                }

                // Check flag
                var isEnabled = unleash.IsEnabled(featureToggleName);

                // Output results
                var messageBuilder = new StringBuilder();
                messageBuilder.Append($"{featureToggleName}={isEnabled} for ");
                messageBuilder.Append($"(UserId={userId},SessionId={sessionId}");

                if (extraParamName != null && extraParamValue != null)
                {
                    messageBuilder.Append($",{extraParamName}={extraParamValue})");
                }
                else
                {
                    messageBuilder.Append(")");
                }

                System.Console.WriteLine(messageBuilder.ToString());

                // Allow metrics to get sent.
                System.Console.WriteLine("Waiting for metrics job to execute...");
                await Task.Delay(TimeSpan.FromSeconds(2));

                System.Console.WriteLine("Metrics job complete (presumably).");

                System.Console.WriteLine("Stopping scheduler...");
            }
            System.Console.WriteLine("Stopped.");
        }