public void DoNotRemoveExpiredValues() { TestUtilities.WriteHeader($"{this}.DoNotRemoveExpiredValues"); var context = new CompareContext($"{this}.DoNotRemoveExpiredValues"); using (var cache = new EventBasedLRUCache <int, string>(11, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, cleanUpIntervalInSeconds: 5, removeExpiredValues: false)) { for (int i = 0; i <= 10; i++) { cache.SetValue(i, i.ToString(), DateTime.UtcNow + TimeSpan.FromSeconds(5)); } Thread.Sleep(5000); // expired items are not removed by default, so all added items should still be in the cache for (int i = 0; i <= 10; i++) { if (!cache.Contains(i)) { context.AddDiff("The key value pair {" + i + ", '" + i.ToString() + "'} should remain in the cache, but the Contains() method returned false."); } } TestUtilities.AssertFailIfErrors(context); } }
public void Contains() { TestUtilities.WriteHeader($"{this}.Contains"); var context = new CompareContext($"{this}.Contains"); using (var cache = new EventBasedLRUCache <int?, string>(10, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: false)) { cache.SetValue(1, "one"); if (!cache.Contains(1)) { context.AddDiff("Cache should contain the key value pair {1, 'one'}, but the Contains() method returned false."); } cache.TryRemove(1, out _); if (cache.Contains(1)) { context.AddDiff("The key value pair {1, 'one'} should have been removed from the cache, but the Contains() method returned true."); } try { cache.Contains(null); context.AddDiff("The parameter passed into the Contains() method was null, but no exception was thrown."); } catch (Exception ex) { if (!ex.GetType().Equals(typeof(ArgumentNullException))) { context.AddDiff("The exception type thrown by Contains(null) was not of type ArgumentNullException."); } } TestUtilities.AssertFailIfErrors(context); } }
public void CacheOverflowTestSequential() { TestUtilities.WriteHeader($"{this}.CacheOverflowTestSequential"); var context = new CompareContext($"{this}.CacheOverflowTestSequential"); var cache = new EventBasedLRUCache <int, string>(1000, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: false); for (int i = 0; i < 100000; i++) { cache.SetValue(i, i.ToString()); } // Cache size should be less than the capacity (somewhere between 800-1000 items). if (cache.LinkedList.Count > 1000) { context.AddDiff("Cache size is greater than the max!"); } // The linked list should be ordered in descending order as the largest items were added last, // and therefore are most recently used. if (!IsDescending(cache.LinkedList)) { context.AddDiff("LRU order was not maintained."); } TestUtilities.AssertFailIfErrors(context); }
public void TryRemove() { TestUtilities.WriteHeader($"{this}.RemoveValue"); var context = new CompareContext($"{this}.RemoveValue"); var cache = new EventBasedLRUCache <int?, string>(1, removeExpiredValues: false); cache.SetValue(1, "one"); if (!cache.TryRemove(1, out _)) { context.AddDiff("The key value pair {1, 'one'} should have been removed from the cache, but the TryRemove() method returned false."); } if (cache.TryRemove(2, out _)) { context.AddDiff("The key value pair {2, 'two'} was never added to the cache, but the TryRemove() method returned true."); } try { cache.TryRemove(null, out _); context.AddDiff("The first parameter passed into the TryRemove() method was null, but no exception was thrown."); } catch (Exception ex) { if (!ex.GetType().Equals(typeof(ArgumentNullException))) { context.AddDiff("The exception type thrown by TryRemove() was not of type ArgumentNullException."); } } TestUtilities.AssertFailIfErrors(context); }
public void CacheOverflowTestMultithreaded() { TestUtilities.WriteHeader($"{this}.CacheOverflowTestMultithreaded"); var context = new CompareContext($"{this}.CacheOverflowTestMultithreaded"); using (var cache = new EventBasedLRUCache <int, string>(10, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: false)) { List <Task> taskList = new List <Task>(); for (int i = 0; i < 100000; i++) { taskList.Add(Task.Factory.StartNew(() => { cache.SetValue(i, i.ToString()); })); } Task.WaitAll(taskList.ToArray()); cache.WaitForProcessing(); // Cache size should be less than the capacity (somewhere between 800 - 1000 items). if (cache.LinkedList.Count() > 1000) { context.AddDiff("Cache size is greater than the max!"); } TestUtilities.AssertFailIfErrors(context); } }
public void MaintainLRUOrder() { TestUtilities.WriteHeader($"{this}.MaintainLRUOrder"); var context = new CompareContext($"{this}.MaintainLRUOrder"); using (var cache = new EventBasedLRUCache <int, string>(10, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: false)) { for (int i = 0; i <= 1000; i++) { cache.SetValue(i, Guid.NewGuid().ToString()); // check that list and map values match up every 10 items // every 10th item should result in two LRU items being removed if (i % 10 == 0 && i != 0) { // wait for the cache events to process cache.WaitForProcessing(); // wait for the last item taken from the queue to execute Thread.Sleep(10); // Cache size should be less than the capacity (somewhere between 8-10 items). if (cache.LinkedList.Count > 10) { context.AddDiff("Cache size is greater than the max!"); } // The linked list should be ordered in descending order as the largest items were added last, // and therefore are most recently used. if (!IsDescending(cache.LinkedList)) { context.AddDiff("LRU order was not maintained."); } } } cache.WaitForProcessing(); // wait for the last item taken from the queue to execute Thread.Sleep(10); // Cache size should be less than the capacity (somewhere between 8-10 items). if (cache.LinkedList.Count > 10) { context.AddDiff("Cache size is greater than the max!"); } // The linked list should be ordered in descending order as the largest items were added last, // and therefore are most recently used. if (!IsDescending(cache.LinkedList)) { context.AddDiff("LRU order was not maintained."); } TestUtilities.AssertFailIfErrors(context); } }
public void SetValue() { TestUtilities.WriteHeader($"{this}.SetValue"); var context = new CompareContext($"{this}.SetValue"); using (var cache = new EventBasedLRUCache <int?, string>(1, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: false)) { Assert.Throws <ArgumentNullException>(() => cache.SetValue(1, null)); cache.SetValue(1, "one"); if (!cache.Contains(1)) { context.AddDiff("The key value pair {1, 'one'} should have been added to the cache, but the Contains() method returned false."); } cache.SetValue(1, "one"); if (!cache.Contains(1)) { context.AddDiff("The key value pair {1, 'one'} should have been added to the cache, but the Contains() method returned false."); } // The LRU item should be removed, allowing this value to be added even though the cache is full. cache.SetValue(2, "two"); if (!cache.Contains(2)) { context.AddDiff("The key value pair {2, 'two'} should have been added to the cache, but the Contains() method returned false."); } try { cache.SetValue(null, "three"); context.AddDiff("The first parameter passed into the SetValue() method was null, but no exception was thrown."); } catch (Exception ex) { if (!ex.GetType().Equals(typeof(ArgumentNullException))) { context.AddDiff("The exception type thrown by Set() was not of type ArgumentNullException."); } } try { cache.SetValue(3, null); context.AddDiff("The second parameter passed into the SetValue() method was null, but no exception was thrown."); } catch (Exception ex) { if (!ex.GetType().Equals(typeof(ArgumentNullException))) { context.AddDiff("The exception type thrown by Set() was not of type ArgumentNullException."); } } TestUtilities.AssertFailIfErrors(context); } }
private void AddItemsToCache(EventBasedLRUCache <int, string> cache, int size, int expiredInSeconds) { for (int i = 0; i <= size; i++) { // Only even values should expire. if (i % 2 == 0) { cache.SetValue(i, i.ToString(), DateTime.UtcNow + TimeSpan.FromSeconds(expiredInSeconds)); } else { cache.SetValue(i, i.ToString()); } } }
public void RemoveExpiredValuesLRU() { int size = 10; int expiredInSeconds = 1; int waitInSeconds = 2 * 1000 * expiredInSeconds; TestUtilities.WriteHeader($"{this}.RemoveExpiredValuesLRU"); var context = new CompareContext($"{this}.RemoveExpiredValuesLRU"); var cache = new EventBasedLRUCache <int, string>(11, removeExpiredValues: true, maintainLRU: true); AddItemsToCache(cache, size, expiredInSeconds); cache.WaitForProcessing(); Thread.Sleep(waitInSeconds); cache.RemoveExpiredValuesLRU(); AssertCache(cache, size, context); }
public void RemoveExpiredValues() { TestUtilities.WriteHeader($"{this}.RemoveExpiredValues"); var context = new CompareContext($"{this}.RemoveExpiredValues"); using (var cache = new EventBasedLRUCache <int, string>(11, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: true)) { for (int i = 0; i <= 10; i++) { // Only even values should expire. if (i % 2 == 0) { cache.SetValue(i, i.ToString(), DateTime.UtcNow + TimeSpan.FromSeconds(5)); } else { cache.SetValue(i, i.ToString()); } } Thread.Sleep(5000); cache.RemoveExpiredValues(); for (int i = 0; i <= 10; i++) { // Only even values should expire. if (i % 2 == 0) { if (cache.Contains(i)) { context.AddDiff("The key value pair {" + i + ", '" + i.ToString() + "'} should have expired and been removed, but the Contains() method returned true."); } } else { if (!cache.Contains(i)) { context.AddDiff("The key value pair {" + i + ", '" + i.ToString() + "'} should remain in the cache, but the Contains() method returned false."); } } } TestUtilities.AssertFailIfErrors(context); } }
public void TryGetValue() { TestUtilities.WriteHeader($"{this}.TryGetValue"); var context = new CompareContext($"{this}.TryGetValue"); using (var cache = new EventBasedLRUCache <int?, string>(2, TaskCreationOptions.LongRunning, tryTakeTimeout: 50, removeExpiredValues: false)) { cache.SetValue(1, "one"); if (!cache.TryGetValue(1, out var value)) { context.AddDiff("The key value pair {1, 'one'} should be in the cache, but the TryGetValue() method returned false."); if (!value.Equals("one")) { context.AddDiff("The corresponding value for key '1' should be 'one' but was '" + value + "'."); } } if (cache.TryGetValue(2, out _)) { context.AddDiff("A key value pair with a key of '2' was never added to the cache, but the TryGetValue() method returned true."); } try { cache.TryGetValue(null, out _); context.AddDiff("The first parameter passed into the TryGetValue() method was null, but no exception was thrown."); } catch (Exception ex) { if (!ex.GetType().Equals(typeof(ArgumentNullException))) { context.AddDiff("The exception type thrown by TryGetValue() was not of type ArgumentNullException."); } } TestUtilities.AssertFailIfErrors(context); } }
private void AssertCache(EventBasedLRUCache <int, string> cache, int size, CompareContext context) { for (int i = 0; i <= size; i++) { // Only even values should expire. if (i % 2 == 0) { if (cache.Contains(i)) { context.AddDiff("The key value pair {" + i + ", '" + i.ToString() + "'} should have expired and been removed, but the Contains() method returned true."); } } else { if (!cache.Contains(i)) { context.AddDiff("The key value pair {" + i + ", '" + i.ToString() + "'} should remain in the cache, but the Contains() method returned false."); } } } TestUtilities.AssertFailIfErrors(context); }