Пример #1
0
        public async Task Null_key_from_identifier_does_not_throw_and_value_does_not_get_cached_async()
        {
            var cache = new MKCache <Item>(
                x => x.Name /* The Name is the key */);

            var item = new Item(name: null !);

            var factoryMock = new Mock <Func <Task <Item> > >();

            factoryMock.Setup(factory => factory()).Returns(Task.FromResult(item));

            var foundItem = await cache.GetOrCreateAsync(item.Id, factoryMock.Object, Expiration);

            factoryMock.Verify(factory => factory(), Times.Once);
            Assert.Same(item, foundItem);

            foundItem = await cache.GetOrCreateAsync("any", factoryMock.Object, Expiration);

            factoryMock.Verify(factory => factory(), Times.Exactly(2));
            Assert.Same(item, foundItem);

            foundItem = await cache.GetOrCreateAsync("any", factoryMock.Object, Expiration);

            factoryMock.Verify(factory => factory(), Times.Exactly(3));
            Assert.Same(item, foundItem);
        }
Пример #2
0
        public async Task Cache_item_expires_async()
        {
            var cache = new MKCache <Item>();

            var item = new Item();

            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(Task.FromResult(item));

            var expirySpan = TimeSpan.FromSeconds(1);

            var foundItem = await cache.GetOrCreateAsync(item.Id, asyncFactoryMock.Object, expirySpan);

            asyncFactoryMock.Verify(factory => factory(), Times.Once);
            Assert.Same(item, foundItem);

            var cachedItem = await cache.GetOrCreateAsync(item.Id, () => Task.FromResult(new Item()), expirySpan);

            Assert.Same(item, cachedItem);

            await Task.Delay(expirySpan * 3);

            var newItem = await cache.GetOrCreateAsync(item.Id, asyncFactoryMock.Object, expirySpan);

            asyncFactoryMock.Verify(factory => factory(), Times.Exactly(2));
        }
Пример #3
0
        public async Task Default_key_cache_can_be_cleared()
        {
            var item = new Item();
            var key  = item.Id;

            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(Task.FromResult(item));

            var cache = new MKCache <Item>();

            var foundItem = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, foundItem);

            var cachedItem = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, cachedItem);

            cache.Clear();

            var _ = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Exactly(2));
        }
Пример #4
0
        public async Task An_item_is_cached_with_the_default_key_async()
        {
            var item = new Item();
            var key  = item.Id;

            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(Task.FromResult(item));

            var cache = new MKCache <Item>();

            var foundItem = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, foundItem);

            var cachedItem = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, cachedItem);

            var _ = await cache.GetOrCreateAsync(item.Name, asyncFactoryMock.Object, Expiration);

            // Delegate invoked a second time, because the item was not found
            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Exactly(2));
        }
Пример #5
0
        public async Task An_item_is_cached_with_a_single_key_async()
        {
            var item = new Item();

            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(Task.FromResult(item));

            var cache = new MKCache <Item>(
                x => x.Name /* Name property is the key */);

            _ = await cache.GetOrCreateAsync(item.Id, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);

            var cachedItem = await cache.GetOrCreateAsync(item.Name, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, cachedItem);

            _ = await cache.GetOrCreateAsync(item.Id, asyncFactoryMock.Object, Expiration);

            // Delegate invoked a second time, because the item was not found using its Id
            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Exactly(2));
        }
Пример #6
0
        public async Task An_item_is_cached_with_multiple_keys_async()
        {
            var item = new Item();
            var key  = item.Id;

            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(Task.FromResult(item));

            var cache = new MKCache <Item>(
                x => x.Id,
                x => x.Name);

            var foundItem = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, foundItem);

            var cachedItem = await cache.GetOrCreateAsync(key, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, cachedItem);

            var cachedItemWithDifferentKey = await cache.GetOrCreateAsync(item.Name, asyncFactoryMock.Object, Expiration);

            asyncFactoryMock.Verify(asyncFactory => asyncFactory(), Times.Once);
            Assert.Same(item, cachedItemWithDifferentKey);
        }
        public async Task Running_async_fetchers_are_reused()
        {
            var item = new Item();

            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(() => Task.Run(async() =>
            {
                // A time long enough for the test to request n concurrent async factories invocations
                await Task.Delay(TimeSpan.FromSeconds(2));
                return(item);
            }));

            var cache = new MKCache <Item>
            {
                ReuseRunningAsyncFetchers = true
            };

            var foundItemTask = cache.GetOrCreateAsync("any", asyncFactoryMock.Object, Expiration);

            // Simulate concurrent request for the same object (same key), while the item is not yet been cached.
            var concurrentFinders = new List <Task <Item> >();
            var n = 100;

            for (int i = 0; i < n; i++)
            {
                concurrentFinders.Add(cache.GetOrCreateAsync("any", asyncFactoryMock.Object, Expiration));
            }

            var foundItem = await foundItemTask;

            // The delegate is invoked only once
            asyncFactoryMock.Verify(asyncFinder => asyncFinder(), Times.Once);

            // The reused and completed task gets mapped into another task for each call (by the cache awaiting it),
            // therefore we might still be needing to await them to complete.
            await Task.WhenAll(concurrentFinders);

            // Even if the Id gets created new each time, the same result has been returned.
            concurrentFinders.ForEach(t => Assert.Equal(t.Result.Id, foundItem.Id));

            // After the async fetcher has completed, the item is stored in cache
            // so the delegate still won't be invoked (but for a different reason).

            var cachedItem = await cache.GetOrCreateAsync("any", asyncFactoryMock.Object, Expiration);

            Assert.Same(item, cachedItem);
            asyncFactoryMock.Verify(asyncFinder => asyncFinder(), Times.Once);
        }
Пример #8
0
        public async Task Null_value_does_not_throw_and_does_not_get_cached_async()
        {
            var cache = new MKCache <Item>();

            var factoryMock = new Mock <Func <Task <Item> > >();

            factoryMock.Setup(factory => factory()).Returns(Task.FromResult(null as Item) !);

            var nullItem = await cache.GetOrCreateAsync("any", factoryMock.Object, Expiration);

            factoryMock.Verify(factory => factory(), Times.Once);
            Assert.Null(nullItem);

            nullItem = await cache.GetOrCreateAsync("any", factoryMock.Object, Expiration);

            factoryMock.Verify(factory => factory(), Times.Exactly(2));
            Assert.Null(nullItem);
        }
        public async Task Running_async_fetchers_are_not_reused_by_configuration()
        {
            var asyncFactoryMock = new Mock <Func <Task <Item> > >();

            asyncFactoryMock.Setup(asyncFactory => asyncFactory()).Returns(() => Task.Run(async() =>
            {
                // A time long enough for the test to request n concurrent async factories invocations
                await Task.Delay(TimeSpan.FromSeconds(2));
                return(new Item());
            }));

            var cache = new MKCache <Item>
            {
                ReuseRunningAsyncFetchers = false
            };

            var foundItemTask = cache.GetOrCreateAsync("any", asyncFactoryMock.Object, Expiration);

            // Simulate concurrent request for the same object (same key), while the item is not yet been cached.
            var concurrentFinders = new List <Task <Item> >();
            var n = 100;

            for (int i = 0; i < n; i++)
            {
                concurrentFinders.Add(cache.GetOrCreateAsync("any", asyncFactoryMock.Object, Expiration));
            }

            var foundItem = await foundItemTask;
            await Task.WhenAll(concurrentFinders);

            // Tasks have not been reused, therefore each item is different.
            concurrentFinders.ForEach(t => Assert.NotEqual(t.Result.Id, foundItem.Id));

            // Ensure that all the delegates have been invoked.
            asyncFactoryMock.Verify(asyncFinder => asyncFinder(), Times.Exactly(n + 1));
        }