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(); }
public async Task Load_WhenTogglesOrEtagFileDoesNotExists_ReturnsEmptyResult( bool toggleCollectionExists, bool etagExists, [Frozen] MemoryToggleCollectionCacheSettings settings, [Frozen] MemoryCache memoryCache, MemoryToggleCollectionCache cache ) { settings.EtagKeyName = "Etag"; settings.ToggleCollectionKeyName = "Toggles"; if (toggleCollectionExists) { var toggleCollection = new ToggleCollection(); memoryCache.Set(settings.ToggleCollectionKeyName, toggleCollection); } if (toggleCollectionExists && etagExists) { var etag = Guid.NewGuid().ToString(); memoryCache.Set(settings.EtagKeyName, etag); } var result = await cache.Load(CancellationToken.None); Assert.Equal(string.Empty, result.InitialETag); Assert.Null(result.InitialToggleCollection); }
public async Task Save_WhenEtagIsNull_ThrowsArgumentNullException( DistributedToggleCollectionCache cache, ToggleCollection toggleCollection ) { await Assert.ThrowsAsync <ArgumentNullException>(() => cache.Save(toggleCollection, null, CancellationToken.None)); }
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(); }
public void Dispose() { if (!cancellationTokenSource.IsCancellationRequested) { cancellationTokenSource.Cancel(); } scheduledTaskManager?.Dispose(); ToggleCollection?.Dispose(); }
public void Serialize_SameAsNewtonSoft(Type type) { Console.WriteLine(type.FullName); Console.WriteLine(); var collection = new ToggleCollection(new List <FeatureToggle>() { new FeatureToggle("one", true, new List <ActivationStrategy>() { new ActivationStrategy("userByName", new Dictionary <string, string>() { { "Demo", "Demo" } }) }), new FeatureToggle("two", false, new List <ActivationStrategy>() { new ActivationStrategy("userByName2", new Dictionary <string, string>() { { "demo", "demo" } }) }) }); var serializer = (IDynamicJsonSerializer)Activator.CreateInstance(type); serializer.TryLoad() .Should().BeTrue(); var expected = JsonConvert.SerializeObject(collection, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() { NamingStrategy = new CamelCaseNamingStrategy() { ProcessDictionaryKeys = false, } } }); expected.Should().Contain("\"Demo\":\"Demo\""); expected.Should().Contain("\"demo\":\"demo\""); using (var ms = new MemoryStream()) { serializer.Serialize(ms, collection); var resultingJson = ms.ConvertToString(); Console.WriteLine(resultingJson); resultingJson.Should().Contain("\"Demo\":\"Demo\""); resultingJson.Should().Contain("\"demo\":\"demo\""); resultingJson.Should().Be(expected); } }
public async Task Save_WhenCancellationTokenIsCanceled_ThrowsOperationCancelledException( DistributedToggleCollectionCache cache, ToggleCollection toggleCollection, string etag ) { var cts = new CancellationTokenSource(); cts.Cancel(); await Assert.ThrowsAsync <OperationCanceledException>(() => cache.Save(toggleCollection, etag, cts.Token)); }
public void test_read_without_file() { UnleashConfig config = UnleashConfig.TheBuilder() .AppName("test") .UnleashAPI("http://unleash.org") .BackupFile("/does/not/exist.json") .Build(); ToggleBackupHandlerFile toggleBackupHandlerFile = new ToggleBackupHandlerFile(config); ToggleCollection toggleCollection = toggleBackupHandlerFile.Read(); Assert.Null(toggleCollection.GetToggle("presentFeature")); }
protected string SerializeToggleCollection(ToggleCollection toggleCollection) { var serializer = CreateSerializer(); using (var memoryStream = new MemoryStream()) { serializer.Serialize(memoryStream, toggleCollection); memoryStream.Seek(0, SeekOrigin.Begin); using (var streamReader = new StreamReader(memoryStream)) { return(streamReader.ReadToEnd()); } } }
/// <inheritdoc /> public Task Save(ToggleCollection toggleCollection, string etag, CancellationToken cancellationToken) { if (toggleCollection == null) { throw new ArgumentNullException(nameof(toggleCollection)); } if (etag == null) { throw new ArgumentNullException(nameof(etag)); } cancellationToken.ThrowIfCancellationRequested(); MemoryCache.Set(Settings.ToggleCollectionKeyName, toggleCollection, Settings.ToggleCollectionEntryOptions); MemoryCache.Set(Settings.EtagKeyName, etag, Settings.EtagEntryOptions); return(Task.CompletedTask); }
public async Task Load_WhenValidToggleAndEtagFilesExist_ReturnsExpectedResult( [Frozen] MemoryToggleCollectionCacheSettings settings, [Frozen] MemoryCache memoryCache, ToggleCollection toggleCollection, string etag ) { settings.EtagKeyName = "Etag"; settings.ToggleCollectionKeyName = "Toggles"; memoryCache.Set(settings.ToggleCollectionKeyName, toggleCollection); memoryCache.Set(settings.EtagKeyName, etag); var cache = new MemoryToggleCollectionCache(settings, memoryCache); var result = await cache.Load(CancellationToken.None); Assert.Equal(etag, result.InitialETag); Assert.Same(toggleCollection, result.InitialToggleCollection); }
public async Task WithHttpClientFactory_RegistersNecessaryServices( [Frozen] Mock <FakeHttpMessageHandler> httpMessageHandler, [Frozen] ToggleCollection expectedToggleCollection, string etag ) { var serviceCollection = new ServiceCollection(); serviceCollection.AddUnleash(s => { s.UnleashApi = new Uri("http://localhost:4242/"); s.AppName = "Test"; s.InstanceTag = "Test"; }) .WithNewtonsoftJsonSerializer() .WithHttpClientFactory( cb => { cb.ConfigurePrimaryHttpMessageHandler(() => httpMessageHandler.Object); }); var serviceProvider = serviceCollection.BuildServiceProvider(true); var unleashApiClientFactory = serviceProvider.GetRequiredService <IUnleashApiClientFactory>(); Assert.IsType <HttpClientFactoryApiClientFactory>(unleashApiClientFactory); var unleashApiClient = unleashApiClientFactory.CreateClient(); Assert.IsType <UnleashApiClient>(unleashApiClient); var concreteUnleashApiClient = (UnleashApiClient)unleashApiClient; var clientRequestHeaders = concreteUnleashApiClient.ClientRequestHeaders; httpMessageHandler.SetupGetFeaturesRequestForSuccess(concreteUnleashApiClient.JsonSerializer, expectedToggleCollection, clientRequestHeaders); var fetchTogglesResult = await unleashApiClient.FetchToggles(etag, CancellationToken.None); var actualToggleCollection = fetchTogglesResult.ToggleCollection; AssertionUtils.AssertToggleCollectionsEquivalent(expectedToggleCollection, actualToggleCollection); }
public void Serialize_WhenValidObject_StringReturned() { //Arrange var value = new ToggleCollection() { Features = new List <FeatureToggle>() { new FeatureToggle() { Name = "example-feature-flag", Enabled = true } } }; //Act var result = serializer.Serialize(value); //Assert Assert.Contains("example-feature-flag", result); Assert.Contains("true", result); }
/// <inheritdoc /> public Task Save(ToggleCollection toggleCollection, string etag, CancellationToken cancellationToken) { if (toggleCollection == null) { throw new ArgumentNullException(nameof(toggleCollection)); } if (etag == null) { throw new ArgumentNullException(nameof(etag)); } cancellationToken.ThrowIfCancellationRequested(); using (var fs = fileSystem.FileOpenCreate(toggleFile)) { jsonSerializer.Serialize(fs, toggleCollection); } fileSystem.WriteAllText(etagFile, etag); return(Task.FromResult <object>(null)); }
public async Task Load_WhenValidToggleAndEtagFilesExist_ReturnsExpectedResult( [Frozen] MemoryDistributedCache distributedCache, ToggleCollection toggleCollection, string etag ) { var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings(); var jsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings); var settings = new DistributedToggleCollectionCacheSettings { EtagEntryOptions = { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }, ToggleCollectionEntryOptions = { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) } }; using (var ms = new MemoryStream()) { jsonSerializer.Serialize(ms, toggleCollection); ms.Seek(0, SeekOrigin.Begin); await distributedCache.SetAsync(settings.ToggleCollectionKeyName, ms.ToArray(), settings.ToggleCollectionEntryOptions, CancellationToken.None).ConfigureAwait(false); await distributedCache.SetStringAsync(settings.EtagKeyName, etag, settings.EtagEntryOptions, CancellationToken.None).ConfigureAwait(false); } var cache = new DistributedToggleCollectionCache(settings, distributedCache, jsonSerializer); var result = await cache.Load(CancellationToken.None); Assert.Equal(etag, result.InitialETag); AssertionUtils.AssertToggleCollectionsEquivalent(toggleCollection, result.InitialToggleCollection); }
public async Task Load_WhenTogglesOrEtagFileDoesNotExists_ReturnsEmptyResult( bool toggleCollectionExists, bool etagExists, [Frozen] DistributedToggleCollectionCacheSettings settings, [Frozen] MemoryDistributedCache distributedCache, DistributedToggleCollectionCache cache ) { var jsonSerializerSettings = new NewtonsoftJsonSerializerSettings(); var jsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings); settings.EtagKeyName = "Etag"; settings.ToggleCollectionKeyName = "Toggles"; if (toggleCollectionExists) { var toggleCollection = new ToggleCollection(); using (var ms = new MemoryStream()) { jsonSerializer.Serialize(ms, toggleCollection); ms.Seek(0, SeekOrigin.Begin); await distributedCache.SetAsync(settings.ToggleCollectionKeyName, ms.ToArray(), settings.ToggleCollectionEntryOptions, CancellationToken.None).ConfigureAwait(false); } } if (toggleCollectionExists && etagExists) { var etag = Guid.NewGuid().ToString(); distributedCache.SetString(settings.EtagKeyName, etag); } var result = await cache.Load(CancellationToken.None); Assert.Equal(string.Empty, result.InitialETag); Assert.Null(result.InitialToggleCollection); }
/// <inheritdoc /> public async Task Save(ToggleCollection toggleCollection, string etag, CancellationToken cancellationToken) { if (toggleCollection == null) { throw new ArgumentNullException(nameof(toggleCollection)); } if (etag == null) { throw new ArgumentNullException(nameof(etag)); } cancellationToken.ThrowIfCancellationRequested(); using (var ms = new MemoryStream()) { jsonSerializer.Serialize(ms, toggleCollection); ms.Seek(0, SeekOrigin.Begin); await distributedCache.SetAsync(Settings.ToggleCollectionKeyName, ms.ToArray(), Settings.ToggleCollectionEntryOptions, cancellationToken).ConfigureAwait(false); await distributedCache.SetStringAsync(Settings.EtagKeyName, etag, Settings.EtagEntryOptions, CancellationToken.None).ConfigureAwait(false); } }
private ToggleCollectionCacheResult(ToggleCollection initialToggleCollection, string initialETag, bool isCacheMiss) { InitialToggleCollection = initialToggleCollection; IsCacheMiss = isCacheMiss; InitialETag = initialETag ?? string.Empty; }
public static ToggleCollectionCacheResult FromResult(ToggleCollection initialToggleCollection, string initialETag) => new ToggleCollectionCacheResult(initialToggleCollection, initialETag, false);
/// <summary> /// Initializes a new instance of the <see cref="DrinkToggle" /> class. /// </summary> /// <param name="toggleCollection">The toggle collection.</param> public DrinkToggle(ToggleCollection toggleCollection) : base(toggleCollection) { }
private static HttpResponseMessage SerializedMessageResponse(IJsonSerializer jsonSerializer, ToggleCollection toggleCollectionResult) { var(payload, etag) = SerializePayloadAndCreateEtag(jsonSerializer, toggleCollectionResult); var response = new HttpResponseMessage { StatusCode = HttpStatusCode.OK, Version = new Version(1, 1), Content = new ByteArrayContent(payload) }; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); response.Headers.ETag = new EntityTagHeaderValue($"\"{etag}\""); return(response); }
public static void AssertToggleCollectionsEquivalent(ToggleCollection expectedToggleCollection, ToggleCollection actualToggleCollection) { Assert.Equal(expectedToggleCollection.Version, actualToggleCollection.Version); AssertFeaturesEquivalent(expectedToggleCollection.Features, actualToggleCollection.Features); }
/// <summary> /// Initializes a new instance of the <see cref="FoodToggle" /> class. /// </summary> /// <param name="toggleCollection">The toggle collection.</param> public FoodToggle(ToggleCollection toggleCollection) : base(toggleCollection) { }
internal static void SetupGetFeaturesRequestForSuccess(this Mock <FakeHttpMessageHandler> mock, IJsonSerializer jsonSerializer, ToggleCollection toggleCollectionResult, UnleashApiClientRequestHeaders requestHeaders) { mock .Setup(mh => mh.Send(It.Is(ApiRequest(HttpMethod.Get, "api/client/features", requestHeaders)))) .Returns(() => SerializedMessageResponse(jsonSerializer, toggleCollectionResult)); }
/// <summary> /// Initializes a new instance of the <see cref="RescueToggle"/> class. /// </summary> /// <param name="toggleCollection">The toggle collection.</param> public RescueToggle(ToggleCollection toggleCollection) : base(toggleCollection) { }