public async Task MemoizeAsync_NotCachedCallWithoutRevokeShouldCacheDataSourceValue() { var revokesSource = new OneTimeSynchronousSourceBlock <string>(); var cache = CreateCache(revokesSource); var memoizer = CreateMemoizer(cache); var dataSourceDelay = 1; var dataSourceResult1 = new Revocable <Thing> { Value = new Thing { Id = "result1" }, RevokeKeys = new List <string> { "x" } }; var dataSource = new ThingFrobber(dataSourceDelay, new List <Revocable <Thing> > { dataSourceResult1 }); RecentlyRevokesCache.TryGetRecentlyRevokedTime(Arg.Any <string>(), Arg.Any <DateTime>()).Returns((DateTime?)null); var result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings()); result.Value.Id.ShouldBe(dataSourceResult1.Value.Id); //call data source and get first value result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings()); result.Value.Id.ShouldBe(dataSourceResult1.Value.Id); //get cached value }
public async Task MemoizeAsync_AfterRefreshRevokeKeysArePreservedInReverseIndexCorrectly() { var revokesSource = new OneTimeSynchronousSourceBlock <string>(); var cache = CreateCache(revokesSource); var memoizer = CreateMemoizer(cache); var dataSource = Substitute.For <IThingFrobber>(); var result1 = new Revocable <Thing> { Value = new Thing { Id = "result1" }, RevokeKeys = new List <string> { "x", "y" } }; var result2 = new Revocable <Thing> { Value = new Thing { Id = "result2" }, RevokeKeys = new List <string> { "x", "y" } }; dataSource.ThingifyTaskRevokable("someString").Returns(result1, result2); await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshTimeSeconds: 0));//refresh in next call cache.RevokeKeysCount.ShouldBe(2); cache.CacheKeyCount.ShouldBe(2); await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings()); cache.CacheKeyCount.ShouldBe(2); cache.RevokeKeysCount.ShouldBe(2); }
public async Task MemoizeAsync_RefreshWithIntefiringRevokeShouldMarkCacheValueAsStaleAndTriggerACallToDataSource() { var cache = CreateCache(new OneTimeSynchronousSourceBlock <string>()); var memoizer = CreateMemoizer(cache); var dataSourceDelay = 1; var dataSourceResult1 = new Revocable <Thing> { Value = new Thing { Id = "result1" }, RevokeKeys = new List <string> { "x" } }; var dataSourceResult2 = new Revocable <Thing> { Value = new Thing { Id = "result2" }, RevokeKeys = new List <string> { "x" } }; var dataSourceResult3 = new Revocable <Thing> { Value = new Thing { Id = "result3" }, RevokeKeys = new List <string> { "x" } }; var dataSource = new ThingFrobber(dataSourceDelay, new List <Revocable <Thing> > { dataSourceResult1, dataSourceResult2, dataSourceResult3 }); //second call to data source will receive a revoke!!! RecentlyRevokesCache.TryGetRecentlyRevokedTime(Arg.Any <string>(), Arg.Any <DateTime>()).Returns((DateTime?)null, TimeFake.UtcNow, (DateTime?)null); var refreshBehavior = RefreshBehavior.TryFetchNewValueOrUseOld; //refresh in next call var result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshTimeSeconds: 0, refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult1.Value.Id); //call data source and get first value result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult2.Value.Id); //refresh triggered, get second value //previous refresh received revoke while in call to remote service and marked item as stale result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult3.Value.Id); //because cached value is stale, another call to data source is triggered and its value is returned result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult3.Value.Id); //latest refresh value was cached and returned }
public async Task MemoizeAsync_NotCachedCallWithIntefiringRevokeShouldMarkCacheValueAsStaleAndTriggerACallToDataSource() { var revokesSource = new OneTimeSynchronousSourceBlock <string>(); var cache = CreateCache(revokesSource); var memoizer = CreateMemoizer(cache); var dataSourceDelay = 1; var dataSourceResult1 = new Revocable <Thing> { Value = new Thing { Id = "result1" }, RevokeKeys = new List <string> { "x" } }; var dataSourceResult2 = new Revocable <Thing> { Value = new Thing { Id = "result2" }, RevokeKeys = new List <string> { "x" } }; var dataSource = new ThingFrobber(dataSourceDelay, new List <Revocable <Thing> > { dataSourceResult1, dataSourceResult2 }); //first call to data source will receive a revoke!!! RecentlyRevokesCache.TryGetRecentlyRevokedTime(Arg.Any <string>(), Arg.Any <DateTime>()).Returns(TimeFake.UtcNow, (DateTime?)null); var result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings()); result.Value.Id.ShouldBe(dataSourceResult1.Value.Id); //call data source and get first value //revoke received while in first call to data source result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings()); result.Value.Id.ShouldBe(dataSourceResult2.Value.Id); //call trigger a call to data source because value is stale and a new data source value is returned result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings()); result.Value.Id.ShouldBe(dataSourceResult2.Value.Id); //cached value is returned }
public async Task MemoizeAsync_RefreshWithoutRevokeShouldCacheNewValue() { var revokesSource = new OneTimeSynchronousSourceBlock <string>(); var cache = CreateCache(revokesSource); var memoizer = CreateMemoizer(cache); var dataSourceDelay = 1; var dataSourceResult1 = new Revocable <Thing> { Value = new Thing { Id = "result1" }, RevokeKeys = new List <string> { "x" } }; var dataSourceResult2 = new Revocable <Thing> { Value = new Thing { Id = "result2" }, RevokeKeys = new List <string> { "x" } }; var dataSource = new ThingFrobber(dataSourceDelay, new List <Revocable <Thing> > { dataSourceResult1, dataSourceResult2 }); RecentlyRevokesCache.TryGetRecentlyRevokedTime(Arg.Any <string>(), Arg.Any <DateTime>()).Returns((DateTime?)null); var refreshBehavior = RefreshBehavior.TryFetchNewValueOrUseOld; //refresh in next call var result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshTimeSeconds: 0, refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult1.Value.Id); //call data source and get first value result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult2.Value.Id); //refresh triggered, get second value from data source and cache result = await(Task <Revocable <Thing> >) memoizer.Memoize(dataSource, ThingifyTaskRevokabkle, new object[] { "someString" }, GetCachingSettings(refreshBehavior: refreshBehavior)); result.Value.Id.ShouldBe(dataSourceResult2.Value.Id); //return refreshed cached value }