@Test
  public void testEntryTtlDestroyEvent() {
    assumeThat(getRegionAttributes().getPartitionAttributes())
        .withFailMessage("the region has partition attributes").isNull();

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

    class DestroyListener extends TestCacheListener<Object, Object> {
      private boolean eventIsExpiration = false;

      @Override
      public void afterDestroyBeforeAddEvent(EntryEvent<Object, Object> event) {
        eventIsExpiration = event.getOperation().isExpiration();
      }

      @Override
      public void afterDestroy2(EntryEvent<Object, Object> event) {
        if (event.isOriginRemote()) {
          assertThat(event.getDistributedMember().equals(getSystem().getDistributedMember()))
              .isFalse();
        } else {
          assertThat(event.getDistributedMember()).isEqualTo(
              getSystem().getDistributedMember());
        }
        assertThat(event.getOperation()).isEqualTo(Operation.EXPIRE_DESTROY);
        assertThat(event.getOldValue()).isEqualTo(value);
        eventIsExpiration = event.getOperation().isExpiration();
      }

      @Override
      public void afterCreate2(EntryEvent<Object, Object> ignored) {}

      @Override
      public void afterUpdate2(EntryEvent<Object, Object> ignored) {}
    }

    vm1.invoke("Create with Listener", () -> {
      RegionFactory<Object, Object> factory1 =
          getCache().createRegionFactory(getRegionAttributes());
      factory1.addCacheListener(destroyListener = new DestroyListener());
      createRegion(name, factory1);
    });

    vm0.invoke("Create with TTL", () -> {
      AttributesFactory<?, ?> factory = new AttributesFactory<>(getRegionAttributes());
      factory.setStatisticsEnabled(true);
      ExpirationAttributes expire = new ExpirationAttributes(timeout, ExpirationAction.DESTROY);
      factory.setEntryTimeToLive(expire);
      if (!getRegionAttributes().getDataPolicy().withReplication()) {
        factory.setDataPolicy(DataPolicy.NORMAL);
        factory.setSubscriptionAttributes(new SubscriptionAttributes(InterestPolicy.ALL));
      }
      System.setProperty(LocalRegion.EXPIRY_MS_PROPERTY, "true");
      try {
        createRegion(name, factory.create());
        ExpiryTask.suspendExpiration();
        // suspend to make sure we can see that the put is distributed to this member
      } finally {
        System.getProperties().remove(LocalRegion.EXPIRY_MS_PROPERTY);
      }
    });

    try {

      // let region create finish before doing put
      vm1.invoke(() -> {
        Region<Object, Object> region = getRootRegion().getSubregion(name);
        DestroyListener dl = (DestroyListener) region.getAttributes().getCacheListeners()[0];
        dl.enableEventHistory();
        region.put(key, value);
        // reset listener after create event
        assertThat(dl.wasInvoked()).isTrue();
        List<CacheEvent<Object, Object>> history = dl.getEventHistory();
        CacheEvent<Object, Object> ce = history.get(0);
        dl.disableEventHistory();
        assertThat(ce.getOperation()).isEqualTo(Operation.CREATE);
      });
      vm0.invoke("Check create received from vm1", () -> {
        final Region<Object, Object> region = getRootRegion().getSubregion(name);
        await("never saw create of " + key)
            .until(() -> region.getEntry(key) != null);
      });

    } finally {
      vm0.invoke("resume expiration", ExpiryTask::permitExpiration);
    }

    // now wait for it to expire
    vm0.invoke("Check local destroy", () -> {
      final Region<Object, Object> region = getRootRegion().getSubregion(name);
      await("never saw expire of " + key)
          .until(() -> region.getEntry(key) == null);
    });

    vm1.invoke("Verify destroyed and event", () -> {
      final Region<Object, Object> region = getRootRegion().getSubregion(name);
      await("never saw expire of " + key)
          .until(() -> region.getEntry(key) == null);

      assertThat(destroyListener.waitForInvocation(555)).isTrue();
      assertThat(((DestroyListener) destroyListener).eventIsExpiration).isTrue();
    });
  }
Tests that an entry in a distributed region that expires with a distributed destroy causes an
event in other VM with isExpiration flag set.
geode-dunit/src/main/java/org/apache/geode/cache30/MultiVMRegionTestCase.java