@Test
  public void testTimeStats() throws CacheException, InterruptedException {
    final long ESTAT_RES = 100; // the resolution, in ms, of entry stats
    String name = getUniqueName();
    Object key = "KEY";
    Object key2 = "KEY2";
    Object value = "VALUE";
    long before;
    long after;
    long oldBefore;
    long oldAfter;

    AttributesFactory factory = new AttributesFactory();
    factory.setScope(Scope.LOCAL);
    factory.setStatisticsEnabled(true);

    before = getCache().cacheTimeMillis();
    Region region = createRegion(name, factory.create());
    CacheStatistics rStats = region.getStatistics();
    CacheStatistics rootStats = getRootRegion().getStatistics();
    after = getCache().cacheTimeMillis();

    assertInRange(before, after, rStats.getLastAccessedTime());
    assertInRange(before, after, rStats.getLastModifiedTime());
    assertInRange(before, after, rootStats.getLastAccessedTime());
    assertInRange(before, after, rootStats.getLastModifiedTime());

    oldBefore = before;
    oldAfter = after;
    Wait.pause(150);
    before = getCache().cacheTimeMillis();
    region.get(key);
    after = getCache().cacheTimeMillis();
    assertInRange(before, after, rStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rStats.getLastModifiedTime());
    assertInRange(before, after, rootStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastModifiedTime());

    Wait.pause(150);
    before = getCache().cacheTimeMillis();
    region.put(key, value);
    CacheStatistics eStats = region.getEntry(key).getStatistics();
    after = getCache().cacheTimeMillis();
    assertInRange(before, after, rStats.getLastAccessedTime());
    assertInRange(before, after, rStats.getLastModifiedTime());
    assertInRange(before, after, rootStats.getLastAccessedTime());
    assertInRange(before, after, rootStats.getLastModifiedTime());

    assertInRange(before - ESTAT_RES, after + ESTAT_RES, eStats.getLastAccessedTime());
    assertInRange(before - ESTAT_RES, after + ESTAT_RES, eStats.getLastModifiedTime());

    oldBefore = before;
    oldAfter = after;
    Wait.pause(150);
    before = getCache().cacheTimeMillis();
    region.get(key);
    after = getCache().cacheTimeMillis();
    assertInRange(before, after, rStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rStats.getLastModifiedTime());
    assertInRange(before, after, rootStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastModifiedTime());
    assertInRange(before - ESTAT_RES, after + ESTAT_RES, eStats.getLastAccessedTime());
    assertInRange(oldBefore - ESTAT_RES, oldAfter + ESTAT_RES, eStats.getLastModifiedTime());

    long oldOldBefore = oldBefore;
    long oldOldAfter = oldAfter;
    oldBefore = before;
    oldAfter = after;
    Wait.pause(150);
    before = getCache().cacheTimeMillis();
    region.create(key2, null);
    CacheStatistics eStats2 = region.getEntry(key2).getStatistics();
    after = getCache().cacheTimeMillis();
    assertInRange(before, after, rStats.getLastAccessedTime());
    assertInRange(before, after, rStats.getLastModifiedTime());
    assertInRange(before, after, rootStats.getLastAccessedTime());
    assertInRange(before, after, rootStats.getLastModifiedTime());

    assertInRange(oldBefore - ESTAT_RES, oldAfter + ESTAT_RES, eStats.getLastAccessedTime());
    assertInRange(oldOldBefore - ESTAT_RES, oldOldAfter + ESTAT_RES, eStats.getLastModifiedTime());

    assertInRange(before - ESTAT_RES, after + ESTAT_RES, eStats2.getLastAccessedTime());
    assertInRange(before - ESTAT_RES, after + ESTAT_RES, eStats2.getLastModifiedTime());

    // Invalidation and destruction do not update the modification/access
    // times
    oldBefore = before;
    oldAfter = after;
    Wait.pause(150);
    before = getCache().cacheTimeMillis();
    region.invalidate(key2);
    after = getCache().cacheTimeMillis();
    assertInRange(oldBefore - ESTAT_RES, oldAfter + ESTAT_RES, eStats2.getLastAccessedTime());
    assertInRange(oldBefore - ESTAT_RES, oldAfter + ESTAT_RES, eStats2.getLastModifiedTime());
    assertInRange(oldBefore, oldAfter, rStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rStats.getLastModifiedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastModifiedTime());

    Wait.pause(150);
    before = getCache().cacheTimeMillis();
    region.destroy(key2);
    after = getCache().cacheTimeMillis();
    assertInRange(oldBefore, oldAfter, rStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rStats.getLastModifiedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastModifiedTime());

    before = getCache().cacheTimeMillis();
    Region sub = region.createSubregion("sub", region.getAttributes());
    after = getCache().cacheTimeMillis();
    assertInRange(before, after, rStats.getLastAccessedTime());
    assertInRange(before, after, rStats.getLastModifiedTime());
    assertInRange(before, after, rootStats.getLastAccessedTime());
    assertInRange(before, after, rootStats.getLastModifiedTime());

    oldBefore = before;
    oldAfter = after;
    before = getCache().cacheTimeMillis();
    sub.destroyRegion();
    after = getCache().cacheTimeMillis();
    assertInRange(oldBefore, oldAfter, rStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rStats.getLastModifiedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastAccessedTime());
    assertInRange(oldBefore, oldAfter, rootStats.getLastModifiedTime());
  }
Tests that the {@linkplain CacheStatistics#getLastAccessedTime last access time} and
{@link CacheStatistics#getLastModifiedTime last modified time} are update appropriately for a
local region and its entries. It also validates that the last modification and last access
times are propagated to parent regions.
geode-core/src/distributedTest/java/org/apache/geode/cache30/CacheStatisticsDUnitTest.java