### Question:
SelfPopulatingCache extends BlockingCache { @Override public Element get(final Object key) throws LockTimeoutException { try { Element element = super.get(key); if (element == null) { Object value = factory.createEntry(key); element = makeAndCheckElement(key, value); put(element); } return element; } catch (LockTimeoutException e) { String message = "Timeout after " + timeoutMillis + " waiting on another thread " + "to fetch object for cache entry \"" + key + "\"."; throw new LockTimeoutException(message, e); } catch (final Throwable throwable) { throwable.printStackTrace(); put(new Element(key, null)); throw new CacheException("Could not fetch object for cache entry with key \"" + key + "\".", throwable); } } SelfPopulatingCache(final Ehcache cache, final CacheEntryFactory factory); @Override Element get(final Object key); void refresh(); void refresh(boolean quiet); Element refresh(Object key); Element refresh(Object key, boolean quiet);  }### Answer:
@Test public void testFetch() throws Exception { LOG.error("."); final Element element = selfPopulatingCache.get("key"); assertEquals("value", element.getValue()); }
@Test public void testFetchUnknown() throws Exception { final CacheEntryFactory factory = new CountingCacheEntryFactory(null); selfPopulatingCache = new SelfPopulatingCache(cache, factory); assertNull(cache.get("key")); }
@Test public void testFetchFail() throws Exception { final Exception exception = new Exception("Failed."); final CacheEntryFactory factory = new CacheEntryFactory() { public Object createEntry(final Object key) throws Exception { throw exception; } }; selfPopulatingCache = new SelfPopulatingCache(cache, factory); try { selfPopulatingCache.get("key"); fail(); } catch (final Exception e) { Thread.sleep(20); assertEquals("Could not fetch object for cache entry with key \"key\".", e.getMessage()); } }
@Test public void testCreateOnce() throws Exception { final String value = "value"; final CountingCacheEntryFactory factory = new CountingCacheEntryFactory(value); selfPopulatingCache = new SelfPopulatingCache(cache, factory); for (int i = 0; i < 5; i++) { assertSame(value, selfPopulatingCache.get("key").getObjectValue()); assertEquals(1, factory.getCount()); } }
@Test public void testCacheEntryFactoryReturningElementMake() throws Exception { final long specialVersionNumber = 54321L; final CacheEntryFactory elementReturningFactory = new CacheEntryFactory() { public Object createEntry(final Object key) throws Exception { Element e = new Element(key, "V_" + key); e.setVersion(specialVersionNumber); return e; } }; selfPopulatingCache = new SelfPopulatingCache(cache, elementReturningFactory); Element e = null; e = selfPopulatingCache.get("key1"); assertEquals("V_key1", e.getValue()); assertEquals(specialVersionNumber, e.getVersion()); e = selfPopulatingCache.get("key2"); assertEquals("V_key2", e.getValue()); assertEquals(specialVersionNumber, e.getVersion()); assertEquals(2, selfPopulatingCache.getSize()); }
@Test public void testCacheEntryFactoryReturningElementBadKey() throws Exception { final CacheEntryFactory elementReturningFactory = new CacheEntryFactory() { public Object createEntry(final Object key) throws Exception { Object modifiedKey = key.toString() + "XX"; Element e = new Element(modifiedKey, "V_" + modifiedKey); return e; } }; selfPopulatingCache = new SelfPopulatingCache(cache, elementReturningFactory); try { selfPopulatingCache.get("key"); fail("Should fail because key was changed"); } catch (final Exception e) { Thread.sleep(20); assertEquals("Could not fetch object for cache entry with key \"key\".", e.getMessage()); } }