@Test
  public void testRemoteCacheListenerInSubregion() {
    assumeThat(supportsSubregions()).isTrue();

    assertThat(getRegionAttributes().getScope().isDistributed()).isTrue();

    final String name = getUniqueName();

    vm0.invoke("Create Root", (SerializableRunnableIF) this::createRootRegion);

    vm1.invoke("Create Region", () -> {
      createRegion(name);
    });

    vm1.invoke("Set listener", () -> {
      final Region<Object, Object> region = getRootRegion().getSubregion(name);
      setListener(new TestCacheListener<Object, Object>() {
        @Override
        public void afterRegionInvalidate2(RegionEvent<Object, Object> event) {
          assertThat(event.getOperation()).isEqualTo(Operation.REGION_INVALIDATE);
          assertThat(event.getRegion()).isEqualTo(region);
          assertThat(event.getOperation().isDistributed()).isTrue();
          assertThat(event.getOperation().isExpiration()).isFalse();
          assertThat(event.isOriginRemote()).isTrue();
          assertThat(event.getDistributedMember()).isEqualTo(event.getCallbackArgument());
        }
      });
      region.getAttributesMutator().addCacheListener(listener());
    });

    vm0.invoke("Invalidate Root Region",
        () -> getRootRegion().invalidateRegion(getSystem().getDistributedMember()));

    vm1.invoke("Verify Invalidate Region", () -> {
      listener().waitForInvocation(3000, 10);

      // Setup listener for next test
      final Region<Object, Object> region = getRootRegion().getSubregion(name);
      setListener(new TestCacheListener<Object, Object>() {
        @Override
        public void afterRegionDestroy2(RegionEvent<Object, Object> event) {
          assertThat(event.getOperation()).isEqualTo(Operation.REGION_DESTROY);
          assertThat(event.getRegion()).isEqualTo(region);
          assertThat(event.getOperation().isDistributed()).isTrue();
          assertThat(event.getOperation().isExpiration()).isFalse();
          assertThat(event.isOriginRemote()).isTrue();
          assertThat(event.getDistributedMember()).isEqualTo(event.getCallbackArgument());
        }
      });
      region.getAttributesMutator().addCacheListener(listener());
    });

    vm0.invoke("Destroy Root Region",
        () -> getRootRegion().destroyRegion(getSystem().getDistributedMember()));

    vm1.invoke("Verify Destroy Region", () -> {
      listener().waitForInvocation(3000, 10);
    });
  }
Tests that a {@link CacheListener} is invoked in a remote VM.
geode-dunit/src/main/java/org/apache/geode/cache30/MultiVMRegionTestCase.java