4

In a sane world, I would have expected the UpdateCallBack property to increment my collection of arguments. But it doesn't: in the final line of this test, the updateArguments collection is expected to be 3 (twice for each Set call and once for the Remove call), but it is empty.

The test is rough and ready, but it should be enough to illustrate that something odd is happening.

Or that I am missing something obvious.

EDIT: This is getting stranger. Based on the question MemoryCache UpdateCallback not working, which says that Thread.Sleep blocks the MemoryCache.Default object, I changed the original Thread.Sleep(5000) call to Task.Factory.StartNew(() => Thread.Sleep(10000)).Wait();. Then, if I comment out the call to MemoryCache.Default.Remove(), the updateArguments collection does indeed get incremented, but only once, and that is when the "PersonKey" cached item expires. The two Set() and one Remove() calls are ignored completely. I'm having a "What the heck" moment.

[Test]
public void TheMemoryCacheMaintainsAMemberAndInvokesTheUpdateCallback()
{
    var person = new Person { GivenName = "Rob", LastName = "Lyndon"};
    var givenName = person.GivenName;
    var lastName = person.LastName;

    var updateArguments = new List<CacheEntryUpdateArguments>();

    MemoryCache.Default.Set("PersonKey", person, CreateNewPolicy(updateArguments));
    var cachedItem = MemoryCache.Default.Get("PersonKey") as Person;
    Assert.IsNotNull(cachedItem);
    Assert.That(cachedItem.GivenName, Is.EqualTo(givenName));
    Assert.That(cachedItem.LastName, Is.EqualTo(lastName));

    person.LastName = "Lyndon - Updated";
    MemoryCache.Default.Set("PersonKey", member, CreateNewPolicy(updateArguments));
    cachedItem = MemoryCache.Default.Get("PersonKey") as Person;
    Assert.IsNotNull(cachedItem);
    Assert.That(cachedItem.GivenName, Is.EqualTo(givenName));
    Assert.That(cachedItem.LastName, Is.EqualTo(lastName + " - Updated"));

    Task.Factory.StartNew(() => Thread.Sleep(10000)).Wait();
    Thread.Sleep(5000);
    Assert.That(updateArguments.Count, Is.EqualTo(3));
}

private static CacheItemPolicy CreateNewPolicy(ICollection<CacheEntryUpdateArguments> updateArguments)
{
    return new CacheItemPolicy
        {
            AbsoluteExpiration = DateTimeOffset.Now.AddSeconds(1),
            UpdateCallback = args => updateArguments.Add(args)
        };
}
Community
  • 1
  • 1
Rob Lyndon
  • 12,089
  • 5
  • 49
  • 74
  • 1
    Where does it fail for you Rob and what's the failure message? – Jamie Dixon Jul 11 '13 at 14:22
  • It fails on the last line. `updateArguments` should be 3 (incremented twice for the `Set` operations and once for the `Remove` operation. – Rob Lyndon Jul 11 '13 at 14:24
  • Looks like you might be expecting the `updateArguments` parameter of `CreateNewPolicy` to be being passed by `ref`. If it's being passed by value then changes made to it inside of `CreateNewPolicy` won't persist outside of the scope of that method. – Jamie Dixon Jul 11 '13 at 14:25
  • But if I put a breakpoint on the `updateArguments.Add()` call, it never gets hit. I'll drop the last `Remove` statement and see what happens. – Rob Lyndon Jul 11 '13 at 14:27
  • When does `UpdateCallback` get executed and who executes it? – Jamie Dixon Jul 11 '13 at 14:29
  • It should be called by the `CacheItemPolicy`, which is set up in the call to `MemoryCache.Default.Set("MemberKey", member, CreateNewPolicy(updateArguments))`. – Rob Lyndon Jul 11 '13 at 14:31
  • 1
    Some side note :- Since you are accessing the caching infrastructure/some kind of a storage, this is not a Unit Test, it is an Integration Test. – Spock Jul 11 '13 at 22:48
  • Ha ha -- good point Raj. And I'm usually a stickler for those details. I'll edit if possible. – Rob Lyndon Jul 12 '13 at 11:35
  • @RobLyndon Thanks. I removed tag 'Unit Tests' and add the 'Integration Tests' if you don't mind :) – Spock Jul 12 '13 at 12:57

0 Answers0