public void TryGet_ChecksLocalCacheThenDistributedCache() { var localCache = new MockLocalCache <int, int>(); var distributedCache = new MockDistributedCache <int, int>(); var twoTierCache = new TwoTierCache <int, int>(localCache, distributedCache, EqualityComparer <int> .Default); for (var i = 1; i <= 100; i++) { twoTierCache.TryGet(i).Result.Success.Should().BeFalse(); localCache.TryGetExecutionCount.Should().Be(i); distributedCache.TryGetExecutionCount.Should().Be(i); } for (var i = 1; i <= 100; i++) { twoTierCache.Set(i, i, TimeSpan.FromSeconds(1)).AsTask().Wait(); localCache.SetExecutionCount.Should().Be(i); distributedCache.SetExecutionCount.Should().Be(i); } for (var i = 1; i <= 100; i++) { var(success, value, _) = twoTierCache.TryGet(i).Result; success.Should().BeTrue(); value.Should().Be(i); localCache.TryGetExecutionCount.Should().Be(100 + i); distributedCache.TryGetExecutionCount.Should().Be(100); } }
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 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 GetMany_SetsValueInLocalCacheIfFoundInDistributedCache() { var localCache = new MockLocalCache <int, int>(); var distributedCache = new MockDistributedCache <int, int>(); var twoTierCache = new TwoTierCache <int, int>(localCache, distributedCache, EqualityComparer <int> .Default); distributedCache .SetMany(Enumerable.Range(0, 50).Select(i => new KeyValuePair <int, int>(i, i)).ToArray(), TimeSpan.FromSeconds(1)) .Wait(); distributedCache.SetManyExecutionCount.Should().Be(1); var values1 = twoTierCache.GetMany(Enumerable.Range(0, 100).ToArray()).Result; values1.Select(kv => kv.Key).Should().BeEquivalentTo(Enumerable.Range(0, 50)); localCache.GetManyExecutionCount.Should().Be(1); localCache.SetExecutionCount.Should().Be(50); distributedCache.GetManyExecutionCount.Should().Be(1); var values2 = twoTierCache.GetMany(Enumerable.Range(0, 50).ToArray()).Result; values2.Select(kv => kv.Key).Should().BeEquivalentTo(Enumerable.Range(0, 50)); localCache.GetManyExecutionCount.Should().Be(2); distributedCache.GetManyExecutionCount.Should().Be(1); }
public void IfAnyMethodsNotConfigured_ThrowsException() { var originalImpl = new DummySingleKeyInterfaceImpl(); var cache = new MockLocalCache <int, int>(); Action action = () => CachedInterfaceFactory.For <IDummySingleKeyInterface>(originalImpl) .Configure <int, int>(x => x.GetAsync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache)) .Configure <int, int>(x => x.GetAsyncCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache)) .Configure <int, int>(x => x.GetSync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache)) .Build(); action.Should().Throw <Exception>().Where(ex => ex.Message.Contains(nameof(IDummySingleKeyInterface.GetSyncCanx))); }
public void OuterKeyAndInnerEnumerableKey_WorksForAllMethodTypes() { var originalImpl = new DummyOuterKeyAndInnerEnumerableKeyInterfaceImpl(); var cache1 = new MockLocalCache <int, int, int>(); var cache2 = new MockLocalCache <int, int, int>(); var cache3 = new MockLocalCache <int, int, int>(); var cache4 = new MockLocalCache <int, int, int>(); var cache5 = new MockLocalCache <int, int, int>(); var cache6 = new MockLocalCache <int, int, int>(); var cachedInterface = CachedInterfaceFactory.For <IDummyOuterKeyAndInnerEnumerableKeyInterface>(originalImpl) .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsync, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache1)) .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsyncCanx, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache2)) .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetSync, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache3)) .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetSyncCanx, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache4)) .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTask, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache5)) .Configure <int, IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTaskCanx, c => c.WithEnumerableKeys <int, IEnumerable <int>, Dictionary <int, int>, int, int>().UseFirstParamAsOuterCacheKey().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache6)) .Build(); cachedInterface.GetAsync(0, new[] { 1 }).Result.Single().Should().Be(new KeyValuePair <int, int>(1, 1)); cache1.GetMany(0, new[] { 1 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(1, 1)); cachedInterface.GetAsyncCanx(0, new[] { 2 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(2, 2)); cache2.GetMany(0, new[] { 2 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(2, 2)); cachedInterface.GetSync(0, new[] { 3 }).Single().Should().Be(new KeyValuePair <int, int>(3, 3)); cache3.GetMany(0, new[] { 3 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(3, 3)); cachedInterface.GetSyncCanx(0, new[] { 4 }, CancellationToken.None).Single().Should().Be(new KeyValuePair <int, int>(4, 4)); cache4.GetMany(0, new[] { 4 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(4, 4)); cachedInterface.GetValueTask(0, new[] { 5 }).Result.Single().Should().Be(new KeyValuePair <int, int>(5, 5)); cache5.GetMany(0, new[] { 5 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(5, 5)); cachedInterface.GetValueTaskCanx(0, new[] { 6 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(6, 6)); cache6.GetMany(0, new[] { 6 }).Should().BeEquivalentTo(new KeyValuePair <int, int>(6, 6)); }
public void EnumerableKey_WorksForAllMethodTypes() { var originalImpl = new DummyEnumerableKeyInterfaceImpl(); var cache1 = new MockLocalCache <int, int>(); var cache2 = new MockLocalCache <int, int>(); var cache3 = new MockLocalCache <int, int>(); var cache4 = new MockLocalCache <int, int>(); var cache5 = new MockLocalCache <int, int>(); var cache6 = new MockLocalCache <int, int>(); var cachedInterface = CachedInterfaceFactory.For <IDummyEnumerableKeyInterface>(originalImpl) .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsync, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache1)) .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetAsyncCanx, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache2)) .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetSync, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache3)) .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetSyncCanx, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache4)) .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTask, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache5)) .Configure <IEnumerable <int>, Dictionary <int, int> >(x => x.GetValueTaskCanx, c => c.WithEnumerableKeys <IEnumerable <int>, Dictionary <int, int>, int, int>().WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache6)) .Build(); cachedInterface.GetAsync(new[] { 1 }).Result.Single().Should().Be(new KeyValuePair <int, int>(1, 1)); cache1.TryGet(1, out _).Should().BeTrue(); cachedInterface.GetAsyncCanx(new[] { 2 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(2, 2)); cache2.TryGet(2, out _).Should().BeTrue(); cachedInterface.GetSync(new[] { 3 }).Single().Should().Be(new KeyValuePair <int, int>(3, 3)); cache3.TryGet(3, out _).Should().BeTrue(); cachedInterface.GetSyncCanx(new[] { 4 }, CancellationToken.None).Single().Should().Be(new KeyValuePair <int, int>(4, 4)); cache4.TryGet(4, out _).Should().BeTrue(); cachedInterface.GetValueTask(new[] { 5 }).Result.Single().Should().Be(new KeyValuePair <int, int>(5, 5)); cache5.TryGet(5, out _).Should().BeTrue(); cachedInterface.GetValueTaskCanx(new[] { 6 }, CancellationToken.None).Result.Single().Should().Be(new KeyValuePair <int, int>(6, 6)); cache6.TryGet(6, out _).Should().BeTrue(); }
public void SingleKey_WorksForAllMethodTypes() { var originalImpl = new DummySingleKeyInterfaceImpl(); var cache1 = new MockLocalCache <int, int>(); var cache2 = new MockLocalCache <int, int>(); var cache3 = new MockLocalCache <int, int>(); var cache4 = new MockLocalCache <int, int>(); var cache5 = new MockLocalCache <int, int>(); var cache6 = new MockLocalCache <int, int>(); var cachedInterface = CachedInterfaceFactory.For <IDummySingleKeyInterface>(originalImpl) .Configure <int, int>(x => x.GetAsync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache1)) .Configure <int, int>(x => x.GetAsyncCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache2)) .Configure <int, int>(x => x.GetSync, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache3)) .Configure <int, int>(x => x.GetSyncCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache4)) .Configure <int, int>(x => x.GetValueTask, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache5)) .Configure <int, int>(x => x.GetValueTaskCanx, c => c.WithTimeToLive(TimeSpan.FromSeconds(1)).WithLocalCache(cache6)) .Build(); cachedInterface.GetAsync(1).Result.Should().Be(1); cache1.TryGet(1, out _).Should().BeTrue(); cachedInterface.GetAsyncCanx(2, CancellationToken.None).Result.Should().Be(2); cache2.TryGet(2, out _).Should().BeTrue(); cachedInterface.GetSync(3).Should().Be(3); cache3.TryGet(3, out _).Should().BeTrue(); cachedInterface.GetSyncCanx(4, CancellationToken.None).Should().Be(4); cache4.TryGet(4, out _).Should().BeTrue(); cachedInterface.GetValueTask(5).Result.Should().Be(5); cache5.TryGet(5, out _).Should().BeTrue(); cachedInterface.GetValueTaskCanx(6, CancellationToken.None).Result.Should().Be(6); cache6.TryGet(6, out _).Should().BeTrue(); }
public void TryGet_SetsValueInLocalCacheIfFoundInDistributedCache() { var localCache = new MockLocalCache <int, int>(); var distributedCache = new MockDistributedCache <int, int>(); var twoTierCache = new TwoTierCache <int, int>(localCache, distributedCache, EqualityComparer <int> .Default); for (var i = 1; i <= 100; i++) { distributedCache.Set(i, i, TimeSpan.FromSeconds(100)); distributedCache.SetExecutionCount.Should().Be(i); } for (var i = 1; i <= 100; i++) { var(success, value, _) = twoTierCache.TryGet(i).Result; success.Should().BeTrue(); value.Should().Be(i); localCache.SetExecutionCount.Should().Be(i); localCache.TryGet(i, out var fromLocalCache).Should().BeTrue(); fromLocalCache.Should().Be(i); } }
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 GetMany_ChecksLocalCacheThenDistributedCache() { var localCache = new MockLocalCache <int, int>(); var distributedCache = new MockDistributedCache <int, int>(); var twoTierCache = new TwoTierCache <int, int>(localCache, distributedCache, EqualityComparer <int> .Default); twoTierCache.GetMany(Enumerable.Range(0, 100).ToArray()).Result.Should().BeEmpty(); localCache.GetManyExecutionCount.Should().Be(1); distributedCache.GetManyExecutionCount.Should().Be(1); twoTierCache.SetMany(Enumerable.Range(0, 50).Select(i => new KeyValuePair <int, int>(i, i)).ToArray(), TimeSpan.FromSeconds(1)); localCache.SetManyExecutionCount.Should().Be(1); distributedCache.SetManyExecutionCount.Should().Be(1); var results1 = twoTierCache.GetMany(Enumerable.Range(0, 100).ToArray()).Result; results1.Select(kv => kv.Key).Should().BeEquivalentTo(Enumerable.Range(0, 50)); foreach (var(key, value) in results1) { value.Should().Be(key); } localCache.GetManyExecutionCount.Should().Be(2); distributedCache.GetManyExecutionCount.Should().Be(2); var results2 = twoTierCache.GetMany(Enumerable.Range(0, 50).ToArray()).Result; results2.Select(kv => kv.Key).Should().BeEquivalentTo(Enumerable.Range(0, 50)); foreach (var(key, value) in results2) { value.Should().Be(key); } localCache.GetManyExecutionCount.Should().Be(3); distributedCache.GetManyExecutionCount.Should().Be(2); }
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 void DontGetFromOrStoreInLocalCacheWhen_ForSingleTierCache_WorksAsExpected( bool flag1, bool flag2, bool flag3, bool flag4) { Func <int, int> originalFunction = key => key; var cache = new MockLocalCache <int, int>(); var config = CachedFunctionFactory .ConfigureFor(originalFunction) .WithLocalCache(cache) .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); } 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 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); }
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 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 void SetMany_EventsAreTriggeredSuccessfully(bool flag1, bool flag2) { var config = new LocalCacheEventsWrapperConfig <int, int, int>(); var successfulResults = new List <(int, IReadOnlyCollection <KeyValuePair <int, int> >, TimeSpan, TimeSpan)>(); var failedResults = new List <(int, IReadOnlyCollection <KeyValuePair <int, int> >, TimeSpan, TimeSpan, Exception)>(); if (flag1) { config.OnSetManyCompletedSuccessfully = (outerKey, values, timeToLive, duration) => { successfulResults.Add((outerKey, values, timeToLive, duration)); }; } if (flag2) { config.OnSetManyException = (outerKey, values, timeToLive, duration, exception) => { failedResults.Add((outerKey, values, timeToLive, duration, exception)); return(values.Any(kv => kv.Key == 6)); }; } var innerCache = new MockLocalCache <int, int, int>(); var cache = new LocalCacheEventsWrapper <int, int, int>(config, innerCache); var values = new[] { new KeyValuePair <int, int>(2, 3), new KeyValuePair <int, int>(4, 5) }; cache.SetMany(1, values, TimeSpan.FromSeconds(1)); if (flag1) { successfulResults.Should().ContainSingle(); successfulResults.Last().Item1.Should().Be(1); successfulResults.Last().Item2.Should().BeEquivalentTo(values); successfulResults.Last().Item3.Should().Be(TimeSpan.FromSeconds(1)); successfulResults.Last().Item4.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { successfulResults.Should().BeEmpty(); } innerCache.ThrowExceptionOnNextAction(); Action action = () => cache.SetMany(1, values, TimeSpan.FromSeconds(1)); action.Should().Throw <Exception>(); if (flag2) { failedResults.Should().ContainSingle(); failedResults.Last().Item1.Should().Be(1); failedResults.Last().Item2.Should().BeEquivalentTo(values); failedResults.Last().Item3.Should().Be(TimeSpan.FromSeconds(1)); failedResults.Last().Item4.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { failedResults.Should().BeEmpty(); } values[1] = new KeyValuePair <int, int>(6, 7); innerCache.ThrowExceptionOnNextAction(); action = () => cache.SetMany(1, values, TimeSpan.FromSeconds(1)); if (flag2) { action(); failedResults.Should().HaveCount(2); failedResults.Last().Item1.Should().Be(1); failedResults.Last().Item2.Should().BeEquivalentTo(values); failedResults.Last().Item3.Should().Be(TimeSpan.FromSeconds(1)); failedResults.Last().Item4.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { action.Should().Throw <Exception>(); failedResults.Should().BeEmpty(); } }
public void TryRemove_EventsAreTriggeredSuccessfully(bool flag1, bool flag2) { var config = new LocalCacheEventsWrapperConfig <int, int, int>(); var successfulResults = new List <(int, int, bool, int, TimeSpan)>(); var failedResults = new List <(int, int, TimeSpan, Exception)>(); if (flag1) { config.OnTryRemoveCompletedSuccessfully = (outerKey, innerKey, found, value, duration) => { successfulResults.Add((outerKey, innerKey, found, value, duration)); }; } if (flag2) { config.OnTryRemoveException = (outerKey, innerKey, duration, exception) => { failedResults.Add((outerKey, innerKey, duration, exception)); return(innerKey == 5); }; } var innerCache = new MockLocalCache <int, int, int>(); var cache = new LocalCacheEventsWrapper <int, int, int>(config, innerCache); cache.TryRemove(1, 2, out _).Should().BeFalse(); if (flag1) { successfulResults.Should().ContainSingle(); successfulResults.Last().Item1.Should().Be(1); successfulResults.Last().Item2.Should().Be(2); successfulResults.Last().Item3.Should().BeFalse(); successfulResults.Last().Item4.Should().Be(0); successfulResults.Last().Item5.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { successfulResults.Should().BeEmpty(); } cache.SetMany(1, new[] { new KeyValuePair <int, int>(3, 4) }, TimeSpan.FromSeconds(1)); cache.TryRemove(1, 3, out _).Should().BeTrue(); if (flag1) { successfulResults.Should().HaveCount(2); successfulResults.Last().Item1.Should().Be(1); successfulResults.Last().Item2.Should().Be(3); successfulResults.Last().Item3.Should().BeTrue(); successfulResults.Last().Item4.Should().Be(4); successfulResults.Last().Item5.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { successfulResults.Should().BeEmpty(); } innerCache.ThrowExceptionOnNextAction(); Action action = () => cache.TryRemove(1, 5, out _); if (flag2) { action(); failedResults.Should().ContainSingle(); failedResults.Last().Item1.Should().Be(1); failedResults.Last().Item2.Should().Be(5); failedResults.Last().Item3.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { action.Should().Throw <Exception>(); failedResults.Should().BeEmpty(); } }
public void GetMany_EventsAreTriggeredSuccessfully(bool flag1, bool flag2) { var config = new LocalCacheEventsWrapperConfig <int, int>(); var successfulResults = new List <(IReadOnlyCollection <int>, IReadOnlyCollection <KeyValuePair <int, int> >, TimeSpan)>(); var failedResults = new List <(IReadOnlyCollection <int>, TimeSpan, Exception)>(); if (flag1) { config.OnGetManyCompletedSuccessfully = (keys, values, duration) => { successfulResults.Add((keys, values, duration)); }; } if (flag2) { config.OnGetManyException = (keys, duration, exception) => { failedResults.Add((keys, duration, exception)); return(keys.Contains(3)); }; } var innerCache = new MockLocalCache <int, int>(); var cache = new LocalCacheEventsWrapper <int, int>(config, innerCache); var keys = new[] { 1, 2 }; cache.Set(1, 2, TimeSpan.FromSeconds(1)); cache.GetMany(keys); if (flag1) { successfulResults.Should().ContainSingle(); successfulResults.Last().Item1.Should().BeEquivalentTo(keys); successfulResults.Last().Item2.ToArray().Should().BeEquivalentTo(new KeyValuePair <int, int>(1, 2)); successfulResults.Last().Item3.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { successfulResults.Should().BeEmpty(); } innerCache.ThrowExceptionOnNextAction(); Action action = () => cache.GetMany(keys); action.Should().Throw <Exception>(); if (flag2) { failedResults.Should().ContainSingle(); failedResults.Last().Item1.Should().BeEquivalentTo(keys); failedResults.Last().Item2.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { failedResults.Should().BeEmpty(); } keys[1] = 3; innerCache.ThrowExceptionOnNextAction(); action = () => cache.GetMany(keys); if (flag2) { action(); failedResults.Should().HaveCount(2); failedResults.Last().Item1.Should().BeEquivalentTo(keys); failedResults.Last().Item2.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { action.Should().Throw <Exception>(); failedResults.Should().BeEmpty(); } }
public void Set_EventsAreTriggeredSuccessfully(bool flag1, bool flag2) { var config = new LocalCacheEventsWrapperConfig <int, int>(); var successfulResults = new List <(int, int, TimeSpan, TimeSpan)>(); var failedResults = new List <(int, int, TimeSpan, TimeSpan, Exception)>(); if (flag1) { config.OnSetCompletedSuccessfully = (key, value, timeToLive, duration) => { successfulResults.Add((key, value, timeToLive, duration)); }; } if (flag2) { config.OnSetException = (key, value, timeToLive, duration, exception) => { failedResults.Add((key, value, timeToLive, duration, exception)); return(key == 5); }; } var innerCache = new MockLocalCache <int, int>(); var cache = new LocalCacheEventsWrapper <int, int>(config, innerCache); cache.Set(1, 2, TimeSpan.FromSeconds(1)); if (flag1) { successfulResults.Should().ContainSingle(); successfulResults.Last().Item1.Should().Be(1); successfulResults.Last().Item2.Should().Be(2); successfulResults.Last().Item3.Should().Be(TimeSpan.FromSeconds(1)); successfulResults.Last().Item4.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { successfulResults.Should().BeEmpty(); } innerCache.ThrowExceptionOnNextAction(); Action action = () => cache.Set(3, 4, TimeSpan.FromSeconds(1)); action.Should().Throw <Exception>(); if (flag2) { failedResults.Should().ContainSingle(); failedResults.Last().Item1.Should().Be(3); failedResults.Last().Item2.Should().Be(4); failedResults.Last().Item3.Should().Be(TimeSpan.FromSeconds(1)); failedResults.Last().Item4.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { failedResults.Should().BeEmpty(); } innerCache.ThrowExceptionOnNextAction(); action = () => cache.Set(5, 6, TimeSpan.FromSeconds(1)); if (flag2) { action(); failedResults.Should().HaveCount(2); failedResults.Last().Item1.Should().Be(5); failedResults.Last().Item2.Should().Be(6); failedResults.Last().Item3.Should().Be(TimeSpan.FromSeconds(1)); failedResults.Last().Item4.Should().BePositive().And.BeCloseTo(TimeSpan.Zero, TimeSpan.FromMilliseconds(100)); } else { action.Should().Throw <Exception>(); failedResults.Should().BeEmpty(); } }
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); } }