public void An_item_is_cached_with_the_default_key() { var item = new Item(); var key = item.Id; var factoryMock = new Mock <Func <Item> >(); factoryMock.Setup(factory => factory()).Returns(item); var cache = new MKCache <Item>(); var foundItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, foundItem); var cachedItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, cachedItem); var _ = cache.GetOrCreate(item.Name, factoryMock.Object, Expiration); // Delegate invoked a second time, because the item was not found factoryMock.Verify(factory => factory(), Times.Exactly(2)); }
public CacheWithKid( MemoryCache cache, MKCache <T> .KeyIdentifier keyIdentifier) { Cache = cache; KeyIdentifier = keyIdentifier; }
public void An_item_is_cached_with_multiple_keys() { var item = new Item(); var key = item.Id; var factoryMock = new Mock <Func <Item> >(); factoryMock.Setup(factory => factory()).Returns(item); var cache = new MKCache <Item>( x => x.Id, x => x.Name); var foundItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, foundItem); var cachedItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, cachedItem); var cachedItemWithDifferentKey = cache.GetOrCreate(item.Name, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, cachedItemWithDifferentKey); }
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)); }
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)); }
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)); }
public void Cache_can_be_cleared() { var item = new Item(); var key = item.Id; var factoryMock = new Mock <Func <Item> >(); factoryMock.Setup(factory => factory()).Returns(item); var cache = new MKCache <Item>(); var foundItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, foundItem); var cachedItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, cachedItem); cache.Clear(); var newlyCachedItem = cache.GetOrCreate(key, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Exactly(2)); Assert.Same(item, newlyCachedItem); }
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); }
public void Deconstruct( out MemoryCache cache, out MKCache <T> .KeyIdentifier keyIdentifier) { cache = Cache; keyIdentifier = KeyIdentifier; }
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 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)); }
public void Removing_missing_item_does_not_throw() { var cache = new MKCache <Item>(); Assert.Equal(0, cache.Count); var missing = cache.Remove("foo"); Assert.Null(missing); }
public void Can_set_item() { var cache = new MKCache <Item>(); var key = "foo"; var existingItem = cache.Get(key); Assert.Null(existingItem); cache.Set(key, new Item(), Expiration); existingItem = cache.Get(key); Assert.NotNull(existingItem); }
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); }
public void Can_inspect_items_count() { var cache = new MKCache <int>(); Assert.Equal(0, cache.Count); cache.GetOrCreate("1", () => 1, Expiration); Assert.Equal(1, cache.Count); cache.GetOrCreate("2", () => 2, Expiration); Assert.Equal(2, cache.Count); cache.Clear(); Assert.Equal(0, cache.Count); }
public void Can_be_disposed() { var cache = new MKCache <Item>(); var item = cache.GetOrCreate("1", () => new Item(), Expiration); cache.Dispose(); // Dispose is not Clear. Assert.Equal(1, cache.Count); // Disposed cache cannot be used anymore. Assert.Throws <ObjectDisposedException>(() => cache.GetOrCreate("1", () => new Item(), Expiration)); }
public void Null_value_does_not_throw_and_does_not_get_cached() { var cache = new MKCache <Item>(); var factoryMock = new Mock <Func <Item> >(); factoryMock.Setup(factory => factory()).Returns((null as Item) !); var nullItem = cache.GetOrCreate("any", factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Null(nullItem); nullItem = cache.GetOrCreate("any", factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Exactly(2)); Assert.Null(nullItem); }
public void Item_can_be_removed() { var cache = new MKCache <Item>(); var key = "foo"; cache.Set(key, new Item(), Expiration); var existingItem = cache.Get(key); Assert.NotNull(existingItem); existingItem = cache.Remove(key); Assert.NotNull(existingItem); existingItem = cache.Get(key); Assert.Null(existingItem); }
public void Can_set_item() { var cache = new MKCache <Item>( x => x.Id, x => x.Name); var item = new Item(); var existingItem = cache.Get(item.Id); Assert.Null(existingItem); cache.Set("", item, Expiration); existingItem = cache.Get(item.Id); Assert.NotNull(existingItem); }
public void Can_inspect_items_count() { var cache = new MKCache <Item>( x => x.Id, x => x.Name); Assert.Equal(0, cache.Count); cache.GetOrCreate("1", () => new Item(), Expiration); Assert.Equal(1, cache.Count); cache.GetOrCreate("name", () => new Item(), Expiration); Assert.Equal(2, cache.Count); cache.Clear(); Assert.Equal(0, cache.Count); }
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 Single_key_item_expires() { var cache = new MKCache <Item>(); var key = "foo"; var existingItem = cache.Get(key); Assert.Null(existingItem); cache.Set(key, new Item(), TimeSpan.FromMilliseconds(100)); existingItem = cache.Get(key); Assert.NotNull(existingItem); await Task.Delay(3000); existingItem = cache.Get(key); Assert.Null(existingItem); }
public void Item_can_be_removed() { var cache = new MKCache <Item>( x => x.Id, x => x.Name); var item = new Item(); cache.Set(item.Id, item, Expiration); var existingItem = cache.Get(item.Id); Assert.NotNull(existingItem); existingItem = cache.Remove(item.Id); Assert.NotNull(existingItem); existingItem = cache.Get(item.Id); Assert.Null(existingItem); }
public async Task Multi_key_item_expires() { var cache = new MKCache <Item>( x => x.Id, x => x.Name); var item = new Item(); var existingItem = cache.Get(item.Id); Assert.Null(existingItem); cache.Set("", item, TimeSpan.FromMilliseconds(100)); existingItem = cache.Get(item.Id); Assert.NotNull(existingItem); await Task.Delay(3000); existingItem = cache.Get(item.Id); Assert.Null(existingItem); }
public void An_item_is_cached_with_a_single_key() { var item = new Item(); var factoryMock = new Mock <Func <Item> >(); factoryMock.Setup(factory => factory()).Returns(item); var cache = new MKCache <Item>( x => x.Name /* Name property is the key */); _ = cache.GetOrCreate(item.Id, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); var cachedItem = cache.GetOrCreate(item.Name, factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, cachedItem); _ = cache.GetOrCreate(item.Id, factoryMock.Object, Expiration); // Delegate invoked a second time, because the item was not found using its Id factoryMock.Verify(factory => factory(), Times.Exactly(2)); }
public void Items_can_be_retrieved_from_the_cache() { var item = new Item(); var factoryMock = new Mock <Func <Item> >(); factoryMock.Setup(factory => factory()).Returns(item); var cache = new MKCache <Item>(); var nullItem = cache.Get("any"); Assert.Null(nullItem); var foundItem = cache.GetOrCreate("any", factoryMock.Object, Expiration); factoryMock.Verify(factory => factory(), Times.Once); Assert.Same(item, foundItem); var cachedItem = cache.Get("any"); Assert.Same(item, cachedItem); }
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)); }