コード例 #1
0
        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();
            }
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        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);
            }
        }
コード例 #4
0
        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));
            }
        }
コード例 #5
0
        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();
        }
コード例 #6
0
        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);
            }
        }
コード例 #7
0
        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();
        }
コード例 #8
0
        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));
            }
        }
コード例 #9
0
        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));
            }
コード例 #10
0
        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();
        }
コード例 #11
0
        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);
        }
コード例 #12
0
        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);
            }
        }
コード例 #13
0
        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);
            }
        }
コード例 #14
0
        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);
        }
コード例 #15
0
        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;
            }
        }
コード例 #16
0
        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;
            }
        }
コード例 #17
0
        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);
            }
        }
コード例 #18
0
        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);
        }
コード例 #19
0
        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);
        }