@Test
  public void testRegionIdleInvalidate() throws CacheException {

    if (getRegionAttributes().getPartitionAttributes() != null) {
      // PR does not support INVALID ExpirationAction
      return;
    }

    final String name = getUniqueName();
    final String subname = getUniqueName() + "-SUB";
    final int timeout = 22; // ms
    final Object key = "KEY";
    final Object value = "VALUE";


    VM vm0 = VM.getVM(0);
    vm0.invoke("testRegionIdleInvalidate", new CacheSerializableRunnable() {
      @Override
      public void run2() throws CacheException {
        TestCacheListener<Object, Object> list = new TestCacheListener<Object, Object>() {
          private int createCount = 0;

          @Override
          public void afterInvalidate2(EntryEvent e) {
            e.getRegion().getCache().getLogger().info("invalidate2 key=" + e.getKey());
          }

          @Override
          public void afterRegionInvalidate2(RegionEvent e) {}

          @Override
          public void afterUpdate2(EntryEvent e) {
            wasInvoked(); // Clear the flag
          }

          @Override
          public void afterCreate2(EntryEvent e) {
            createCount++;
            // we only expect one create; all the rest should be updates
            assertEquals(1, createCount);
            wasInvoked(); // Clear the flag
          }
        };
        RegionFactory<Object, Object> factory =
            getCache().createRegionFactory(getRegionAttributes());
        ExpirationAttributes expire =
            new ExpirationAttributes(timeout, ExpirationAction.INVALIDATE);
        factory.setRegionIdleTimeout(expire);
        factory.setStatisticsEnabled(true);
        factory.addCacheListener(list);

        Region<Object, Object> region;
        Region<Object, Object> sub;
        Region.Entry entry;
        long tilt;
        System.setProperty(LocalRegion.EXPIRY_MS_PROPERTY, "true");
        ExpiryTask.suspendExpiration();
        try {
          region = createRegion(name, factory);
          region.put(key, value);
          tilt = System.currentTimeMillis() + timeout;
          entry = region.getEntry(key);
          assertEquals(value, entry.getValue());
          sub = factory.createSubregion(region, subname);
        } finally {
          System.getProperties().remove(LocalRegion.EXPIRY_MS_PROPERTY);
          ExpiryTask.permitExpiration();
        }
        waitForInvalidate(entry, tilt, 10);

        assertTrue(list.waitForInvocation(333));


        // The next phase of the test verifies that a get will cause the
        // expiration time to be extended.
        // For this phase we don't worry about actually expiring but just
        // making sure the expiration time gets extended.
        final int EXPIRATION_MS = 9000;
        region.getAttributesMutator().setRegionIdleTimeout(
            new ExpirationAttributes(EXPIRATION_MS, ExpirationAction.INVALIDATE));

        LocalRegion lr = (LocalRegion) region;
        {
          ExpiryTask expiryTask = lr.getRegionIdleExpiryTask();
          region.put(key, value);
          long createExpiry = expiryTask.getExpirationTime();
          long changeTime = Wait.waitForExpiryClockToChange(lr, createExpiry - EXPIRATION_MS);
          region.put(key, "VALUE2");
          long putExpiry = expiryTask.getExpirationTime();
          assertTrue(
              "CLOCK went back in time! Expected putBaseExpiry=" + (putExpiry - EXPIRATION_MS)
                  + " to be >= than changeTime=" + changeTime,
              (putExpiry - EXPIRATION_MS - changeTime) >= 0);
          assertTrue(
              "expected putExpiry=" + putExpiry + " to be > than createExpiry=" + createExpiry,
              (putExpiry - createExpiry) > 0);
          changeTime = Wait.waitForExpiryClockToChange(lr, putExpiry - EXPIRATION_MS);
          region.get(key);
          long getExpiry = expiryTask.getExpirationTime();
          assertTrue(
              "CLOCK went back in time! Expected getBaseExpiry=" + (getExpiry - EXPIRATION_MS)
                  + " to be >= than changeTime=" + changeTime,
              (getExpiry - EXPIRATION_MS - changeTime) >= 0);
          assertTrue("expected getExpiry=" + getExpiry + " to be > than putExpiry=" + putExpiry,
              (getExpiry - putExpiry) > 0);

          changeTime = Wait.waitForExpiryClockToChange(lr, getExpiry - EXPIRATION_MS);
          sub.put(key, value);
          long subPutExpiry = expiryTask.getExpirationTime();
          assertTrue(
              "CLOCK went back in time! Expected subPutBaseExpiry=" + (subPutExpiry - EXPIRATION_MS)
                  + " to be >= than changeTime=" + changeTime,
              (subPutExpiry - EXPIRATION_MS - changeTime) >= 0);
          assertTrue(
              "expected subPutExpiry=" + subPutExpiry + " to be > than getExpiry=" + getExpiry,
              (subPutExpiry - getExpiry) > 0);
          changeTime = Wait.waitForExpiryClockToChange(lr, subPutExpiry - EXPIRATION_MS);
          sub.get(key);
          long subGetExpiry = expiryTask.getExpirationTime();
          assertTrue(
              "CLOCK went back in time! Expected subGetBaseExpiry=" + (subGetExpiry - EXPIRATION_MS)
                  + " to be >= than changeTime=" + changeTime,
              (subGetExpiry - EXPIRATION_MS - changeTime) >= 0);
          assertTrue("expected subGetExpiry=" + subGetExpiry + " to be > than subPutExpiry="
              + subPutExpiry, (subGetExpiry - subPutExpiry) > 0);
        }
      }
    });
  }
Tests that a region that remains idle for a given amount of time is invalidated. Also tests
that accessing an entry of a region or a subregion counts as an access.
geode-dunit/src/main/java/org/apache/geode/cache30/RegionTestCase.java