We have a certain class which sometimes makes some tests fail… the code is old (consider it legacy) but it’s not that bad… but we just can’t figure out why it sometimes causes tests the fail.
Here’s an example of a test that occasionally fails:
[Test]
public void TestGet_CacheableObjectReturned()
{
TestCacheableObject cacheableObject = new TestCacheableObject("test", 60000);
CacheProvider.GetInstance().Put(cacheableObject);
try
{
Assert.AreSame(cacheableObject, CacheProvider.GetInstance().Get("test"));
}
finally
{
CacheProvider.GetInstance().Remove("test");
}
}
If it fails, it’s on the following line:
Assert.AreSame(cacheableObject, CacheProvider.GetInstance().Get("test"));
Sometimes, the Get method of the CacheProvider returns null in this test, even though the cacheable object has just been added to the CacheProvider.
Here’s the code of the CacheProvider:
public class CacheProvider
{
private static object monitor = new object();
private static CacheProvider _instance;
private IDictionary<object, CacheableObject> _cacheDictionary;
private CacheProvider()
{
_cacheDictionary = new Dictionary<object, CacheableObject>();
}
public static CacheProvider GetInstance()
{
lock (monitor)
{
if (_instance == null)
{
_instance = new CacheProvider();
}
}
return _instance;
}
public void Put(CacheableObject value)
{
if (ContainsKey(value.Key))
{
Remove(value.Key);
}
value.Provider = this;
_cacheDictionary.Add(value.Key, value);
value.StartTicking();
}
public CacheableObject Get(object key)
{
if (_cacheDictionary.ContainsKey(key))
{
return _cacheDictionary[key];
}
return null;
}
public void Remove(object key)
{
_cacheDictionary.Remove(key);
}
public bool ContainsKey(object key)
{
return _cacheDictionary.ContainsKey(key);
}
}
This is the code of the CacheableObject class:
public abstract class CacheableObject
{
private object _key;
private CacheProvider _cacheProvider;
private Timer _timer;
protected abstract double GetTimeToLive();
public CacheableObject(object key)
{
_key = key;
}
public void StartTicking()
{
_timer = new Timer(GetTimeToLive());
_timer.Elapsed += Timer_Elapsed;
_timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
_timer.Stop();
Provider.Remove(this.Key);
}
public object Key
{
get
{
return _key;
}
}
public CacheProvider Provider
{
get
{
return _cacheProvider;
}
set
{
_cacheProvider = value;
}
}
}
And this is the code of the TestCacheableObject that is used in the failing test:
public class TestCacheableObject : CacheableObject
{
private double _ttl;
public TestCacheableObject(string key, double ttl)
: base(key)
{
_ttl = ttl;
}
protected override double GetTimeToLive()
{
return _ttl;
}
}
I can’t for the life of me figure out why the test above fails sometimes. It happens very occassionaly, sometimes it even takes weeks or months before it fails again. It’s not just the test above, it’s basically every test that uses the CacheProvider’s ContainsKey method (either directly or indirectly) that fails sometimes.
Important note to consider: when these tests fail, they take about 10ms…
If anyone has a clue what could possibly cause this, i’d be very willing to hear it