public void WithTimeToLiveFactory_SetsTimeToLiveCorrectly() { Func <int, int> originalFunction = key => key; var cache = new MockLocalCache <int, int>(); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(cache) .WithTimeToLiveFactory(key => TimeSpan.FromMilliseconds(key)) .Build(); foreach (var key in new[] { 250, 500, 1000 }) { CheckTimeToLiveForKey(key); } void CheckTimeToLiveForKey(int key) { cachedFunction(key); Thread.Sleep(TimeSpan.FromMilliseconds(key / 2)); cache.TryGet(key, out _).Should().BeTrue(); Thread.Sleep(TimeSpan.FromMilliseconds(key)); cache.TryGet(key, out _).Should().BeFalse(); } }
public void CustomRequestType_SucceedsIfConfigured(bool configureRequestConverter) { Func <SortedSet <int>, Dictionary <int, int> > originalFunction = keys => keys.ToDictionary(k => k); var config = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <SortedSet <int>, Dictionary <int, int>, int, int>() .WithTimeToLive(TimeSpan.FromSeconds(1)) .WithLocalCache(new MockLocalCache <int, int>()); if (!configureRequestConverter) { Action action = () => config.Build(); action.Should().Throw <Exception>(); return; } var cachedFunction = config .WithRequestConverter(k => new SortedSet <int>(k.ToArray())) .Build(); var results = cachedFunction(new SortedSet <int>(Enumerable.Range(0, 100))); results.Should().Match(values => values.All(kv => kv.Key == kv.Value)); results.Keys.Should().BeEquivalentTo(Enumerable.Range(0, 100)); }
public void DisableCaching_WorksAsExpected(bool disableCaching) { Func <int, int> originalFunction = key => key; var cache = new MockLocalCache <int, int>(); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .DisableCaching(disableCaching) .Build(); cachedFunction(1); if (disableCaching) { cache.TryGetExecutionCount.Should().Be(0); cache.SetExecutionCount.Should().Be(0); } else { cache.TryGetExecutionCount.Should().Be(1); cache.SetExecutionCount.Should().Be(1); } }
public void WithTimeToLiveFactory_NotCalledIfKeyWillNotBeStoredInCache() { Func <int, int> originalFunction = key => key; var timeToLiveFactoryExecutionCount = 0; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(new MockLocalCache <int, int>()) .DontStoreInCacheWhen((k, _) => k % 2 == 0) .WithTimeToLiveFactory(TimeToLiveFactory) .Build(); for (var i = 0; i < 100; i++) { cachedFunction(i); } timeToLiveFactoryExecutionCount.Should().Be(50); TimeSpan TimeToLiveFactory(int key) { Interlocked.Increment(ref timeToLiveFactoryExecutionCount); if (key % 2 == 0) { throw new Exception(); } return(TimeSpan.FromSeconds(1)); } }
public async Task WithCancellationToken_CancellationPropagatesToUnderlyingFunction() { var wasCancelled = false; Func <int, CancellationToken, Task <int> > originalFunction = async(key, cancellationToken) => { cancellationToken.Register(() => wasCancelled = true); await Task.Delay(TimeSpan.FromSeconds(10), cancellationToken).ConfigureAwait(false); return(key); }; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(new MemoryCache <int, int>(i => i.ToString())) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMilliseconds(100)); Func <Task <int> > func = () => cachedFunction(1, cancellationTokenSource.Token); await func.Should().ThrowExactlyAsync <TaskCanceledException>().ConfigureAwait(false); // Give the cancellation token time to complete the callback await Task.Delay(TimeSpan.FromMilliseconds(10)).ConfigureAwait(false); wasCancelled.Should().BeTrue(); }
public void Concurrent_CorrectValuesAreReturned(bool useMemoryCache) { var delay = TimeSpan.FromMilliseconds(100); Func <IEnumerable <int>, Task <Dictionary <int, int> > > originalFunction = async keys => { await Task.Delay(delay).ConfigureAwait(false); return(keys.ToDictionary(k => k)); }; var config = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>() .WithTimeToLive(TimeSpan.FromSeconds(1)); if (useMemoryCache) { config.WithMemoryCache(); } else { config.WithDictionaryCache(); } var cachedFunction = config.Build(); var timer = Stopwatch.StartNew(); RunTasks(); timer.Elapsed.Should().BeGreaterThan(delay); timer.Restart(); RunTasks(); // All values should be cached this time timer.Elapsed.Should().BeLessThan(delay); void RunTasks() { var tasks = Enumerable .Range(0, 5) .Select(async _ => { for (var i = 0; i < 5; i++) { var keys = Enumerable.Range(i, 10).ToList(); var values = await cachedFunction(keys).ConfigureAwait(false); values.Select(kv => kv.Key).Should().BeEquivalentTo(keys); } }) .ToArray(); Task.WaitAll(tasks); } }
public CachedFunctionWithSingleKey() { var cache = new DictionaryCache <int, int>(); cache.Set(1, 1, TimeSpan.FromHours(1)); _func = CachedFunctionFactory .ConfigureFor <int, int>(OriginalFunc) .WithTimeToLive(TimeSpan.FromTicks(1)) .WithLocalCache(cache) .Build(); }
public void DifferentRequestType_Succeeds(string typeName) { switch (typeName) { case "Array": RunTest <int[]>(k => k.ToArray()); break; case "HashSet": RunTest <HashSet <int> >(k => new HashSet <int>(k)); break; case "List": RunTest <List <int> >(k => k.ToList()); break; default: throw new Exception(); } void RunTest <T>(Func <IEnumerable <int>, T> converter) where T : IEnumerable <int> { Func <T, Dictionary <int, int> > originalFunction = keys => { return(keys.ToDictionary(k => k)); }; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <T, Dictionary <int, int>, int, int>() .WithTimeToLive(TimeSpan.FromSeconds(1)) .WithLocalCache(new MockLocalCache <int, int>()) .Build(); var results1 = cachedFunction(converter(Enumerable.Range(0, 100))); results1.Should().HaveCount(100); results1.Should().Match(values => values.All(kv => kv.Key == kv.Value)); results1.Select(kv => kv.Key).OrderBy(k => k).Should().BeEquivalentTo(Enumerable.Range(0, 100)); var results2 = cachedFunction(converter(Enumerable.Range(50, 100))); results2.Should().HaveCount(100); results2.Should().Match(values => values.All(kv => kv.Key == kv.Value)); results2.Select(kv => kv.Key).OrderBy(k => k).Should().BeEquivalentTo(Enumerable.Range(50, 100)); } }
public void DifferentResponseType_Succeeds(string typeName) { switch (typeName) { case "ConcurrentDictionary": RunTest <ConcurrentDictionary <int, int> >(d => new ConcurrentDictionary <int, int>(d)); break; case "ListKeyValuePair": RunTest <List <KeyValuePair <int, int> > >(d => d.ToList()); break; case "ArrayKeyValuePair": RunTest <KeyValuePair <int, int>[]>(d => d.ToArray()); break; default: throw new Exception(); } void RunTest <T>(Func <Dictionary <int, int>, T> converter) where T : IEnumerable <KeyValuePair <int, int> > { Func <IEnumerable <int>, T> originalFunction = keys => { return(converter(keys.ToDictionary(k => k))); }; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <IEnumerable <int>, T, int, int>() .WithTimeToLive(TimeSpan.FromSeconds(1)) .WithLocalCache(new MockLocalCache <int, int>()) .Build(); var results = cachedFunction(Enumerable.Range(0, 100)); results.Should().Match(values => values.All(kv => kv.Key == kv.Value)); results.Select(kv => kv.Key).OrderBy(k => k).Should().BeEquivalentTo(Enumerable.Range(0, 100)); }
public CachedFunctionWithEnumerableKeys() { _oneHitResults = BuildResults(_oneHit); _oneMissResults = BuildResults(_oneMiss); _oneHitAndOneMissResults = BuildResults(_oneHitAndOneMiss); _oneHundredHitsResults = BuildResults(_oneHundredHits); _oneHundredMissesResults = BuildResults(_oneHundredMisses); _oneHundredHitsAndOneHundredMissesResults = BuildResults(_oneHundredHitsAndOneHundredMisses); var cache = new DictionaryCache <int, int>(); for (var i = 0; i < 100; i++) { cache.Set(i, i, TimeSpan.FromHours(1)); } _func = CachedFunctionFactory .ConfigureFor((IList <int> x) => OriginalFunc(x)) .WithEnumerableKeys <IList <int>, Dictionary <int, int>, int, int>() .WithTimeToLive(TimeSpan.FromTicks(1)) .WithLocalCache(cache) .Build(); }
public void WithTimeToLive_SetsTimeToLiveCorrectly(int timeToLiveMs) { Func <int, int> originalFunction = key => key; var cache = new MockLocalCache <int, int>(); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromMilliseconds(timeToLiveMs)) .Build(); cachedFunction(1); Thread.Sleep(timeToLiveMs / 2); cachedFunction(1); cache.HitsCount.Should().Be(1); Thread.Sleep(timeToLiveMs); cachedFunction(1); cache.HitsCount.Should().Be(1); }
public void CacheStats_PopulatedCorrectly(bool localCacheEnabled, bool distributedCacheEnabled) { CacheGetStats lastCacheStats = default; Func <int, int> originalFunction = key => key; var config = CachedFunctionFactory.ConfigureFor(originalFunction) .WithTimeToLive(TimeSpan.FromMinutes(1)) .OnResult(r => lastCacheStats = r.CacheStats) .DontGetFromCacheWhen(k => k == 1) .DontGetFromLocalCacheWhen(k => k == 2) .DontGetFromDistributedCacheWhen(k => k == 3); if (localCacheEnabled) { var localCache = new MockLocalCache <int, int>(); localCache.Set(4, 4, TimeSpan.FromMinutes(1)); config.WithLocalCache(localCache); } if (distributedCacheEnabled) { var distributedCache = new MockDistributedCache <int, int>(); distributedCache.Set(4, 4, TimeSpan.FromMinutes(1)); distributedCache.Set(5, 5, TimeSpan.FromMinutes(1)); config.WithDistributedCache(distributedCache); } var cachedFunction = config.Build(); var cacheEnabled = localCacheEnabled || distributedCacheEnabled; for (var i = 1; i <= 5; i++) { cachedFunction(i).Should().Be(i); VerifyCacheStats(i); } void VerifyCacheStats(int key) { var localCacheKeyRequested = localCacheEnabled && key != 1 && key != 2; var localCacheHit = localCacheEnabled && key == 4; var distributedCacheKeyRequested = distributedCacheEnabled && !localCacheHit && key != 1 && key != 3; var distributedCacheHit = distributedCacheKeyRequested && (key == 4 || key == 5); var cacheKeyRequested = localCacheKeyRequested || distributedCacheKeyRequested; var cacheHit = localCacheHit || distributedCacheHit; lastCacheStats.CacheEnabled.Should().Be(cacheEnabled); lastCacheStats.CacheKeyRequested.Should().Be(cacheKeyRequested); lastCacheStats.CacheSkipped.Should().Be(cacheEnabled && !cacheKeyRequested); lastCacheStats.CacheHit.Should().Be(cacheHit); lastCacheStats.CacheMiss.Should().Be(cacheKeyRequested && !cacheHit); lastCacheStats.LocalCacheEnabled.Should().Be(localCacheEnabled); lastCacheStats.LocalCacheKeyRequested.Should().Be(localCacheKeyRequested); lastCacheStats.LocalCacheSkipped.Should().Be(localCacheEnabled && !localCacheKeyRequested); lastCacheStats.LocalCacheHit.Should().Be(localCacheHit); lastCacheStats.LocalCacheMiss.Should().Be(localCacheKeyRequested && !localCacheHit); lastCacheStats.DistributedCacheEnabled.Should().Be(distributedCacheEnabled); lastCacheStats.DistributedCacheKeyRequested.Should().Be(distributedCacheKeyRequested); lastCacheStats.DistributedCacheSkipped.Should().Be(distributedCacheEnabled && !localCacheHit && !distributedCacheKeyRequested); lastCacheStats.DistributedCacheHit.Should().Be(distributedCacheHit); lastCacheStats.DistributedCacheMiss.Should().Be(distributedCacheKeyRequested && !distributedCacheHit); } }
public void OnResult_EventsAreTriggeredAsExpected() { var cache = new MockLocalCache <string, int>(); SuccessfulRequestEvent <int, string, int> lastSuccess = default; ExceptionEvent <int, string> lastException = default; var first = true; var exceptionMessage = Guid.NewGuid().ToString(); Func <int, CancellationToken, int> originalFunction = (p, cancellationToken) => { ThrowIfFirst(); return(-p); }; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(x => x.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .OnResult(r => lastSuccess = r, ex => lastException = ex) .Build(); Func <int> func = () => cachedFunction(1, CancellationToken.None); func.Should().Throw <Exception>(); CheckException(); func().Should().Be(-1); CheckSuccess(false); func().Should().Be(-1); CheckSuccess(true); void ThrowIfFirst() { if (!first) { return; } first = false; throw new Exception(exceptionMessage); } void CheckSuccess(bool wasCached) { var now = DateTime.UtcNow; lastSuccess.Parameters.Should().Be(1); lastSuccess.Key.Should().Be("1"); lastSuccess.Value.Should().Be(-1); lastSuccess.Start.Should().BeWithin(TimeSpan.FromMilliseconds(100)).Before(now); lastSuccess.Duration.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); lastSuccess.CacheStats.CacheHit.Should().Be(wasCached); } void CheckException() { var now = DateTime.UtcNow; lastException.Parameters.Should().Be(1); lastException.Key.Should().Be("1"); lastException.Start.Should().BeWithin(TimeSpan.FromMilliseconds(100)).Before(now); lastException.Duration.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); lastException.Exception.Message.Should().Be(exceptionMessage); } }
public async Task With8Params_WorksAsExpected(string functionType, bool hasCancellationToken) { var cache = new MockLocalCache <int, int>(); switch (functionType) { case "async" when hasCancellationToken: { Func <int, int, int, int, int, int, int, int, CancellationToken, Task <int> > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8, cancellationToken) => Task.FromResult(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey((p1, p2, p3, p4, p5, p6, p7, p8) => p1) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, 2, 3, 4, 5, 6, 7, 8, CancellationToken.None).ConfigureAwait(false)).Should().Be(36); break; } case "async": { Func <int, int, int, int, int, int, int, int, Task <int> > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8) => Task.FromResult(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey((p1, p2, p3, p4, p5, p6, p7, p8) => p1) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, 2, 3, 4, 5, 6, 7, 8).ConfigureAwait(false)).Should().Be(36); break; } case "sync" when hasCancellationToken: { Func <int, int, int, int, int, int, int, int, CancellationToken, int> originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8, cancellationToken) => p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey((p1, p2, p3, p4, p5, p6, p7, p8) => p1) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, 8, CancellationToken.None).Should().Be(36); break; } case "sync": { Func <int, int, int, int, int, int, int, int, int> originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8) => p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey((p1, p2, p3, p4, p5, p6, p7, p8) => p1) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, 8).Should().Be(36); break; } case "valuetask" when hasCancellationToken: { Func <int, int, int, int, int, int, int, int, CancellationToken, ValueTask <int> > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8, cancellationToken) => new ValueTask <int>(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey((p1, p2, p3, p4, p5, p6, p7, p8) => p1) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, 8, CancellationToken.None).Result.Should().Be(36); break; } case "valuetask": { Func <int, int, int, int, int, int, int, int, ValueTask <int> > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8) => new ValueTask <int>(p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey((p1, p2, p3, p4, p5, p6, p7, p8) => p1) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, 8).Result.Should().Be(36); break; } } cache.TryGet(1, out var value).Should().BeTrue(); value.Should().Be(36); }
public void DontGetFromOrStoreInDistributedCacheWhen_ForSingleTierCache_WorksAsExpected( bool flag1, bool flag2, bool flag3, bool flag4) { Func <int, int> originalFunction = key => key; var cache = new MockDistributedCache <int, int>(); var config = CachedFunctionFactory .ConfigureFor(originalFunction) .WithDistributedCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)); if (flag1) { config.DontGetFromDistributedCacheWhen(key => key % 2 == 0); } if (flag2) { config.DontStoreInDistributedCacheWhen((key, _) => key % 3 == 0); } if (flag3) { config.DontGetFromDistributedCacheWhen(key => key % 5 == 0); } if (flag4) { config.DontStoreInDistributedCacheWhen((key, _) => key % 7 == 0); } var cachedFunction = config.Build(); var previousTryGetExecutionCount = 0; var previousSetExecutionCount = 0; for (var i = 0; i < 100; i++) { cachedFunction(i); var currentTryGetExecutionCount = cache.TryGetExecutionCount; var currentSetExecutionCount = cache.SetExecutionCount; var skipGet = flag1 && i % 2 == 0 || flag3 && i % 5 == 0; var skipSet = flag2 && i % 3 == 0 || flag4 && i % 7 == 0; if (skipGet) { currentTryGetExecutionCount.Should().Be(previousTryGetExecutionCount); } else { currentTryGetExecutionCount.Should().Be(previousTryGetExecutionCount + 1); } if (skipSet) { currentSetExecutionCount.Should().Be(previousSetExecutionCount); } else { currentSetExecutionCount.Should().Be(previousSetExecutionCount + 1); } previousTryGetExecutionCount = currentTryGetExecutionCount; previousSetExecutionCount = currentSetExecutionCount; } }
public void DontGetFromOrStoreInLocalCacheWhen_DontGetFromOrStoreInDistributedCacheWhen_WorksAsExpected( bool flag1, bool flag2, bool flag3, bool flag4, bool flag5, bool flag6, bool flag7, bool flag8) { Func <int, int> originalFunction = key => key; var localCache = new MockLocalCache <int, int>(); var distributedCache = new MockDistributedCache <int, int>(); var config = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(localCache) .WithDistributedCache(distributedCache) .WithTimeToLive(TimeSpan.FromSeconds(1)); if (flag1) { config.DontGetFromLocalCacheWhen(key => key % 2 == 0); } if (flag2) { config.DontStoreInLocalCacheWhen((key, _) => key % 3 == 0); } if (flag3) { config.DontGetFromLocalCacheWhen(key => key % 5 == 0); } if (flag4) { config.DontStoreInLocalCacheWhen((key, _) => key % 7 == 0); } if (flag5) { config.DontGetFromDistributedCacheWhen(key => key % 11 == 0); } if (flag6) { config.DontStoreInDistributedCacheWhen((key, _) => key % 13 == 0); } if (flag7) { config.DontGetFromDistributedCacheWhen(key => key % 17 == 0); } if (flag8) { config.DontStoreInDistributedCacheWhen((key, _) => key % 19 == 0); } var cachedFunction = config.Build(); var previousLocalTryGetExecutionCount = 0; var previousLocalSetExecutionCount = 0; var previousDistributedTryGetExecutionCount = 0; var previousDistributedSetExecutionCount = 0; for (var i = 0; i < 100; i++) { cachedFunction(i); var currentLocalTryGetExecutionCount = localCache.TryGetExecutionCount; var currentLocalSetExecutionCount = localCache.SetExecutionCount; var currentDistributedTryGetExecutionCount = distributedCache.TryGetExecutionCount; var currentDistributedSetExecutionCount = distributedCache.SetExecutionCount; var skipLocalGet = flag1 && i % 2 == 0 || flag3 && i % 5 == 0; var skipLocalSet = flag2 && i % 3 == 0 || flag4 && i % 7 == 0; var skipDistributedGet = flag5 && i % 11 == 0 || flag7 && i % 17 == 0; var skipDistributedSet = flag6 && i % 13 == 0 || flag8 && i % 19 == 0; if (skipLocalGet) { currentLocalTryGetExecutionCount.Should().Be(previousLocalTryGetExecutionCount); } else { currentLocalTryGetExecutionCount.Should().Be(previousLocalTryGetExecutionCount + 1); } if (skipLocalSet) { currentLocalSetExecutionCount.Should().Be(previousLocalSetExecutionCount); } else { currentLocalSetExecutionCount.Should().Be(previousLocalSetExecutionCount + 1); } if (skipDistributedGet) { currentDistributedTryGetExecutionCount.Should().Be(previousDistributedTryGetExecutionCount); } else { currentDistributedTryGetExecutionCount.Should().Be(previousDistributedTryGetExecutionCount + 1); } if (skipDistributedSet) { currentDistributedSetExecutionCount.Should().Be(previousDistributedSetExecutionCount); } else { currentDistributedSetExecutionCount.Should().Be(previousDistributedSetExecutionCount + 1); } previousLocalTryGetExecutionCount = currentLocalTryGetExecutionCount; previousLocalSetExecutionCount = currentLocalSetExecutionCount; previousDistributedTryGetExecutionCount = currentDistributedTryGetExecutionCount; previousDistributedSetExecutionCount = currentDistributedSetExecutionCount; } }
public async Task With6Params_WorksAsExpected(string functionType, bool hasCancellationToken) { var cache = new MockLocalCache <int, int>(); var input = Enumerable.Range(1, 10).ToArray(); var expectedOutput = input.ToDictionary(x => x); switch (functionType) { case "async" when hasCancellationToken: { Func <int, int, int, int, int, IEnumerable <int>, CancellationToken, Task <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6, cancellationToken) => Task.FromResult(p6.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, 2, 3, 4, 5, input, CancellationToken.None).ConfigureAwait(false)).Should().BeEquivalentTo(expectedOutput); break; } case "async": { Func <int, int, int, int, int, IEnumerable <int>, Task <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6) => Task.FromResult(p6.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, 2, 3, 4, 5, input).ConfigureAwait(false)).Should().BeEquivalentTo(expectedOutput); break; } case "sync" when hasCancellationToken: { Func <int, int, int, int, int, IEnumerable <int>, CancellationToken, Dictionary <int, int> > originalFunction = (p1, p2, p3, p4, p5, p6, cancellationToken) => p6.ToDictionary(x => x); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, input, CancellationToken.None).Should().BeEquivalentTo(expectedOutput); break; } case "sync": { Func <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int> > originalFunction = (p1, p2, p3, p4, p5, p6) => p6.ToDictionary(x => x); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, input).Should().BeEquivalentTo(expectedOutput); break; } case "valuetask" when hasCancellationToken: { Func <int, int, int, int, int, IEnumerable <int>, CancellationToken, ValueTask <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6, cancellationToken) => new ValueTask <Dictionary <int, int> >(p6.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, input, CancellationToken.None).Result.Should().BeEquivalentTo(expectedOutput); break; } case "valuetask": { Func <int, int, int, int, int, IEnumerable <int>, ValueTask <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6) => new ValueTask <Dictionary <int, int> >(p6.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, input).Result.Should().BeEquivalentTo(expectedOutput); break; } } for (var i = 1; i <= 10; i++) { cache.TryGet(i, out var value).Should().BeTrue(); value.Should().Be(i); } }
public async Task With8Params_WorksAsExpected(string functionType, bool hasCancellationToken) { var cache = new MockLocalCache <int, int, int>(); var input = Enumerable.Range(1, 10).ToArray(); var expectedOutput = input.ToDictionary(x => x); switch (functionType) { case "async" when hasCancellationToken: { Func <int, int, int, int, int, int, int, IEnumerable <int>, CancellationToken, Task <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8, cancellationToken) => Task.FromResult(p8.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1 + p2 + p3 + p4 + p5 + p6 + p7) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, 2, 3, 4, 5, 6, 7, input, CancellationToken.None).ConfigureAwait(false)).Should().BeEquivalentTo(expectedOutput); break; } case "async": { Func <int, int, int, int, int, int, int, IEnumerable <int>, Task <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8) => Task.FromResult(p8.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1 + p2 + p3 + p4 + p5 + p6 + p7) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, 2, 3, 4, 5, 6, 7, input).ConfigureAwait(false)).Should().BeEquivalentTo(expectedOutput); break; } case "sync" when hasCancellationToken: { Func <int, int, int, int, int, int, int, IEnumerable <int>, CancellationToken, Dictionary <int, int> > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8, cancellationToken) => p8.ToDictionary(x => x); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1 + p2 + p3 + p4 + p5 + p6 + p7) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, input, CancellationToken.None).Should().BeEquivalentTo(expectedOutput); break; } case "sync": { Func <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int> > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8) => p8.ToDictionary(x => x); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1 + p2 + p3 + p4 + p5 + p6 + p7) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, input).Should().BeEquivalentTo(expectedOutput); break; } case "valuetask" when hasCancellationToken: { Func <int, int, int, int, int, int, int, IEnumerable <int>, CancellationToken, ValueTask <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8, cancellationToken) => new ValueTask <Dictionary <int, int> >(p8.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1 + p2 + p3 + p4 + p5 + p6 + p7) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, input, CancellationToken.None).Result.Should().BeEquivalentTo(expectedOutput); break; } case "valuetask": { Func <int, int, int, int, int, int, int, IEnumerable <int>, ValueTask <Dictionary <int, int> > > originalFunction = (p1, p2, p3, p4, p5, p6, p7, p8) => new ValueTask <Dictionary <int, int> >(p8.ToDictionary(x => x)); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithEnumerableKeys <int, int, int, int, int, int, int, IEnumerable <int>, Dictionary <int, int>, int, int>() .WithOuterCacheKey((p1, p2, p3, p4, p5, p6, p7) => p1 + p2 + p3 + p4 + p5 + p6 + p7) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, 2, 3, 4, 5, 6, 7, input).Result.Should().BeEquivalentTo(expectedOutput); break; } } cache.GetMany(28, input).Should().BeEquivalentTo(expectedOutput); }
public async Task With1Param_WorksAsExpected(string functionType, bool hasCancellationToken) { var cache = new MockLocalCache <string, int>(); switch (functionType) { case "async" when hasCancellationToken: { Func <int, CancellationToken, Task <int> > originalFunction = (p, cancellationToken) => Task.FromResult(p); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(p => p.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, CancellationToken.None).ConfigureAwait(false)).Should().Be(1); break; } case "async": { Func <int, Task <int> > originalFunction = Task.FromResult; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(p => p.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1).ConfigureAwait(false)).Should().Be(1); break; } case "sync" when hasCancellationToken: { Func <int, CancellationToken, int> originalFunction = (p, cancellationToken) => p; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(p => p.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1, CancellationToken.None).Should().Be(1); break; } case "sync": { Func <int, int> originalFunction = p => p; var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(p => p.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); cachedFunction(1).Should().Be(1); break; } case "valuetask" when hasCancellationToken: { Func <int, CancellationToken, ValueTask <int> > originalFunction = (p, cancellationToken) => new ValueTask <int>(p); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(p => p.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1, CancellationToken.None).ConfigureAwait(false)).Should().Be(1); break; } case "valuetask": { Func <int, ValueTask <int> > originalFunction = p => new ValueTask <int>(p); var cachedFunction = CachedFunctionFactory .ConfigureFor(originalFunction) .WithCacheKey(p => p.ToString()) .WithLocalCache(cache) .WithTimeToLive(TimeSpan.FromSeconds(1)) .Build(); (await cachedFunction(1).ConfigureAwait(false)).Should().Be(1); break; } } cache.TryGet("1", out var value).Should().BeTrue(); value.Should().Be(1); }