@Test
  public void testMirroredDataFromNonMirrored() {
    assumeThat(supportsReplication()).isTrue();

    final String name = getUniqueName();
    final Object key1 = "KEY1";
    final Object value1 = "VALUE1";
    final Object key2 = "KEY2";
    final Object value2 = "VALUE2";
    final Object key3 = "KEY3";
    final Object value3 = "VALUE3";

    class MirroredDataFromNonMirroredListener extends TestCacheListener<Object, Object> {
      // use modifiable ArrayLists
      private final List<Object> expectedKeys = new ArrayList<>(Arrays.asList(key1, key2, key3));
      private final List<Object> expectedValues =
          new ArrayList<>(Arrays.asList(value1, value2, value3));

      @Override
      public synchronized void afterCreate2(EntryEvent<Object, Object> event) {
        int index = expectedKeys.indexOf(event.getKey());
        assertThat(index >= 0).isTrue();
        assertThat(event.getNewValue()).isEqualTo(expectedValues.remove(index));
        expectedKeys.remove(index);
        logger.info("afterCreate called in "
            + "MirroredDataFromNonMirroredListener for key:" + event.getKey());
      }
    }

    vm0.invoke("Create Mirrored Region", () -> {
      RegionAttributes<Object, Object> ra = getRegionAttributes();
      RegionFactory<Object, Object> factory = getCache().createRegionFactory(ra);
      if (ra.getEvictionAttributes() == null
          || !ra.getEvictionAttributes().getAction().isOverflowToDisk()) {
        factory.setDiskStoreName(null);
      }
      factory.setDataPolicy(DataPolicy.REPLICATE);
      factory.addCacheListener(new MirroredDataFromNonMirroredListener());
      createRegion(name, factory);
    });

    vm2.invoke("Populate non-mirrored region", () -> {
      RegionAttributes<Object, Object> ra = getRegionAttributes();
      RegionFactory<Object, Object> regionFactory = getCache().createRegionFactory(ra);
      if (ra.getEvictionAttributes() == null
          || !ra.getEvictionAttributes().getAction().isOverflowToDisk()) {
        regionFactory.setDiskStoreName(null);
      }
      regionFactory.setDataPolicy(DataPolicy.NORMAL);

      Region<Object, Object> region1 = createRegion(name, regionFactory);
      region1.put(key1, value1);
      region1.put(key2, value2);
      region1.put(key3, value3);
      flushIfNecessary(region1);
    });

    // Destroy the local entries so we know that they are not found by
    // a netSearch
    vm2.invoke("Remove local entries", () -> {
      Region<Object, Object> region = getRootRegion().getSubregion(name);
      region.localDestroy(key1);
      region.localDestroy(key2);
      region.localDestroy(key3);
      flushIfNecessary(region);
    });

    vm0.invoke("Verify keys/values and listener", () -> {
      Region<Object, Object> region = getRootRegion().getSubregion(name);

      Region.Entry entry1 = region.getEntry(key1);
      assertThat(entry1).isNotNull();
      assertThat(entry1.getValue()).isEqualTo(value1);

      Region.Entry entry2 = region.getEntry(key2);
      assertThat(entry2).isNotNull();
      assertThat(entry2.getValue()).isEqualTo(value2);

      Region.Entry entry3 = region.getEntry(key3);
      assertThat(entry3).isNotNull();
      assertThat(entry3.getValue()).isEqualTo(value3);

      MirroredDataFromNonMirroredListener mirroredDataFromNonMirroredListener =
          (MirroredDataFromNonMirroredListener) region.getAttributes().getCacheListeners()[0];

      assertThat(mirroredDataFromNonMirroredListener.wasInvoked()).isTrue();
      assertThat(mirroredDataFromNonMirroredListener.expectedKeys.isEmpty()).describedAs(
          "expectedKeys should be empty, but was: "
              + mirroredDataFromNonMirroredListener.expectedKeys)
          .isTrue();
    });
  }
Tests that a mirrored region gets data pushed to it from a non-mirrored region and the
afterCreate event is invoked on a listener.
geode-dunit/src/main/java/org/apache/geode/cache30/MultiVMRegionTestCase.java