Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement non-blocking synchronous evaluation (snapshot API) #81

Merged
merged 9 commits into from
Apr 29, 2024
41 changes: 5 additions & 36 deletions src/ConfigCat.Client.Tests/ConfigCacheTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Threading;
using System.Threading.Tasks;
using ConfigCat.Client.Cache;
using ConfigCat.Client.Tests.Fakes;
using ConfigCat.Client.Tests.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
Expand Down Expand Up @@ -70,20 +71,20 @@ public async Task ConfigCache_Override_ManualPoll_Works()
});

configCacheMock.Verify(c => c.SetAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
configCacheMock.Verify(c => c.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
configCacheMock.Verify(c => c.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);

var actual = await client.GetValueAsync("stringDefaultCat", "N/A");

Assert.AreEqual("N/A", actual);
configCacheMock.Verify(c => c.SetAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Never);
configCacheMock.Verify(c => c.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
configCacheMock.Verify(c => c.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(2));

await client.ForceRefreshAsync();

actual = await client.GetValueAsync("stringDefaultCat", "N/A");
Assert.AreEqual("Cat", actual);
configCacheMock.Verify(c => c.SetAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
configCacheMock.Verify(c => c.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(3));
configCacheMock.Verify(c => c.GetAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(4));
}

[TestMethod]
Expand Down Expand Up @@ -242,40 +243,8 @@ public void CacheKeyGeneration_ShouldBePlatformIndependent(string sdkKey, string
public void CachePayloadSerialization_ShouldBePlatformIndependent(string configJson, string timeStamp, string httpETag, string expectedPayload)
{
var timeStampDateTime = DateTimeOffset.ParseExact(timeStamp, "o", CultureInfo.InvariantCulture).UtcDateTime;
var pc = new ProjectConfig(configJson, configJson.Deserialize<Config>(), timeStampDateTime, httpETag);
var pc = new ProjectConfig(configJson, Config.Deserialize(configJson.AsMemory()), timeStampDateTime, httpETag);

Assert.AreEqual(expectedPayload, ProjectConfig.Serialize(pc));
}

private sealed class FakeExternalCache : IConfigCatCache
{
public volatile string? CachedValue = null;

public string? Get(string key) => this.CachedValue;

public Task<string?> GetAsync(string key, CancellationToken cancellationToken = default) => Task.FromResult(Get(key));

public void Set(string key, string value) => this.CachedValue = value;

public Task SetAsync(string key, string value, CancellationToken cancellationToken = default)
{
Set(key, value);
return Task.FromResult(0);
}
}

private sealed class FaultyFakeExternalCache : IConfigCatCache
{
public string? Get(string key) => throw new ApplicationException("Operation failed :(");

public Task<string?> GetAsync(string key, CancellationToken cancellationToken = default) => Task.FromResult(Get(key));

public void Set(string key, string value) => throw new ApplicationException("Operation failed :(");

public Task SetAsync(string key, string value, CancellationToken cancellationToken = default)
{
Set(key, value);
return Task.FromResult(0);
}
}
}
71 changes: 71 additions & 0 deletions src/ConfigCat.Client.Tests/ConfigCatClientSnapshotTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using ConfigCat.Client.Cache;
using ConfigCat.Client.ConfigService;
using ConfigCat.Client.Configuration;
using ConfigCat.Client.Evaluation;
using ConfigCat.Client.Override;
using ConfigCat.Client.Tests.Fakes;
using ConfigCat.Client.Tests.Helpers;
using ConfigCat.Client.Utils;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace ConfigCat.Client.Tests;

[TestClass]
public class ConfigCatClientSnapshotTests
{
[TestMethod]
public void DefaultInstanceDoesNotThrow()
{
const string key = "key";
const string defaultValue = "";

var snapshot = default(ConfigCatClientSnapshot);

Assert.AreEqual(ClientCacheState.NoFlagData, snapshot.CacheState);
Assert.IsNull(snapshot.FetchedConfig);
CollectionAssert.AreEqual(ArrayUtils.EmptyArray<string>(), snapshot.GetAllKeys().ToArray());
Assert.AreEqual("", snapshot.GetValue(key, defaultValue));
var evaluationDetails = snapshot.GetValueDetails(key, defaultValue);
Assert.IsNotNull(evaluationDetails);
Assert.AreEqual(key, evaluationDetails.Key);
Assert.AreEqual(defaultValue, evaluationDetails.Value);
Assert.IsTrue(evaluationDetails.IsDefaultValue);
Assert.IsNotNull(evaluationDetails.ErrorMessage);
}

[TestMethod]
public void CanMockSnapshot()
{
const ClientCacheState cacheState = ClientCacheState.HasUpToDateFlagData;
var fetchedConfig = new Config();
var keys = new[] { "key1", "key2" };
var evaluationDetails = new EvaluationDetails<string>("key1", "value");

var mock = new Mock<IConfigCatClientSnapshot>();
mock.SetupGet(m => m.CacheState).Returns(cacheState);
mock.SetupGet(m => m.FetchedConfig).Returns(fetchedConfig);
mock.Setup(m => m.GetAllKeys()).Returns(keys);
mock.Setup(m => m.GetValue(evaluationDetails.Key, It.IsAny<string>(), It.IsAny<User?>())).Returns(evaluationDetails.Value);
mock.Setup(m => m.GetValueDetails(evaluationDetails.Key, It.IsAny<string>(), It.IsAny<User?>())).Returns(evaluationDetails);

var snapshot = new ConfigCatClientSnapshot(mock.Object);

Assert.AreEqual(cacheState, snapshot.CacheState);
Assert.AreEqual(fetchedConfig, snapshot.FetchedConfig);
CollectionAssert.AreEqual(keys, snapshot.GetAllKeys().ToArray());
Assert.AreEqual(evaluationDetails.Value, snapshot.GetValue(evaluationDetails.Key, ""));
Assert.AreSame(evaluationDetails, snapshot.GetValueDetails(evaluationDetails.Key, ""));
}
}
Loading
Loading