@Test
  public void test034NotifyAllUpdates() throws CacheException {
    final String name = getName();

    disconnectAllFromDS();

    for (VM vm : new VM[] {vm0, vm1}) {
      // Create the cache servers with distributed, mirrored region
      vm.invoke("Create Cache Server", () -> {
        CacheLoader<Object, Object> cl = new CacheLoader<Object, Object>() {
          @Override
          public Object load(LoaderHelper helper) {
            return helper.getKey();
          }

          @Override
          public void close() {

          }
        };
        RegionFactory<Object, Object> factory =
            getBridgeServerMirroredAckRegionAttributes(cl);
        createRegion(name, factory);
        startBridgeServer(0);
      });
    }

    // Create cache server clients
    final int numberOfKeys = 10;
    final String host0 = NetworkUtils.getServerHostName();
    final int vm0Port = vm0.invoke(ConnectionPoolDUnitTest::getCacheServerPort);
    final int vm1Port = vm1.invoke(ConnectionPoolDUnitTest::getCacheServerPort);
    Stream.of(vm2, vm3).forEach(vm -> {
      logger.info("before create client");
      vm.invoke("Create Cache Server Client", () -> {
        // reset all static listener variables in case this is being rerun in a subclass
        numberOfAfterInvalidates = 0;
        numberOfAfterCreates = 0;
        numberOfAfterUpdates = 0;
        getLonerSystem();
        // create the region
        RegionFactory<Object, Object> factory = getCache().createRegionFactory();
        factory.setScope(Scope.LOCAL);
        factory.setConcurrencyChecksEnabled(false);
        // create bridge writer
        configureConnectionPool(factory, host0, new int[] {vm0Port, vm1Port}, true, -1,
            -1, null);
        createRegion(name, factory);
      });
    });

    // Initialize each client with entries (so that afterInvalidate is called)
    Stream.of(vm2, vm3).forEach(vm -> {
      logger.info("before initialize client");
      vm.invoke("Initialize Client", () -> {
        numberOfAfterInvalidates = 0;
        numberOfAfterCreates = 0;
        numberOfAfterUpdates = 0;
        Region<Object, Object> region = getRootRegion().getSubregion(name);
        for (int i = 0; i < numberOfKeys; i++) {
          assertThat("key-" + i).isEqualTo(region.get("key-" + i));
        }
      });
    });

    // Add a CacheListener to both vm2 and vm3
    vm2.invoke("Add CacheListener 1", () -> {
      Region<Object, Object> region = getRootRegion().getSubregion(name);
      CacheListener<Object, Object> listener = new CacheListenerAdapter<Object, Object>() {
        @Override
        public void afterCreate(EntryEvent e) {
          numberOfAfterCreates++;
          logger.info("vm2 numberOfAfterCreates: " + numberOfAfterCreates);
        }

        @Override
        public void afterUpdate(EntryEvent e) {
          numberOfAfterUpdates++;
          logger.info("vm2 numberOfAfterUpdates: " + numberOfAfterUpdates);
        }

        @Override
        public void afterInvalidate(EntryEvent e) {
          numberOfAfterInvalidates++;
          logger.info("vm2 numberOfAfterInvalidates: " + numberOfAfterInvalidates);
        }
      };
      region.getAttributesMutator().addCacheListener(listener);
      region.registerInterestRegex(".*", false, false);
    });

    vm3.invoke("Add CacheListener 2", () -> {
      Region<Object, Object> region = getRootRegion().getSubregion(name);
      CacheListener<Object, Object> listener = new CacheListenerAdapter<Object, Object>() {
        @Override
        public void afterCreate(EntryEvent e) {
          numberOfAfterCreates++;
        }

        @Override
        public void afterUpdate(EntryEvent e) {
          numberOfAfterUpdates++;
        }

        @Override
        public void afterInvalidate(EntryEvent e) {
          numberOfAfterInvalidates++;
        }
      };
      region.getAttributesMutator().addCacheListener(listener);
      region.registerInterestRegex(".*", false, false);
    });

    vm2.invoke(() -> await().untilAsserted(() -> {
      Region<Object, Object> region = getRootRegion().getSubregion(name);
      for (int i = 0; i < numberOfKeys; i++) {
        assertThat("key-" + i).isEqualTo(region.get("key-" + i));
      }
    }));

    // Use vm2 to put new values
    // This should cause 10 afterUpdates to vm2 and 10 afterInvalidates to vm3
    vm2.invoke("Put New Values", () -> {
      Region<Object, Object> region = getRootRegion().getSubregion(name);
      for (int i = 0; i < 10; i++) {
        region.put("key-" + i, "key-" + i);
      }
    });

    vm2.invoke(() -> {
      await("VM2 should not have received any afterCreate messages")
          .until(() -> ConnectionPoolDUnitTest.getNumberOfAfterCreates() == 0);
      await("VM2 should not have received any afterInvalidate messages")
          .until(() -> ConnectionPoolDUnitTest.getNumberOfAfterInvalidates() == 0);
    });

    long vm2AfterUpdates = vm2.invoke(ConnectionPoolDUnitTest::getNumberOfAfterUpdates);
    long vm3AfterInvalidates = vm3.invoke(ConnectionPoolDUnitTest::getNumberOfAfterInvalidates);
    assertThat(vm2AfterUpdates)
        .describedAs("VM2 received " + vm2AfterUpdates
            + " afterUpdate messages. It should have received " + numberOfKeys)
        .isEqualTo(numberOfKeys);
    assertThat(vm3AfterInvalidates)
        .describedAs("VM3 received " + vm3AfterInvalidates
            + " afterInvalidate messages. It should have received " + numberOfKeys)
        .isEqualTo(numberOfKeys);
  }
Tests 'notify-all' client updates. This test verifies that: - only invalidates are sent as part
of the 'notify-all' mode of client updates - originators of updates are not sent invalidates -
non-originators of updates are sent invalidates - multiple invalidates are not sent for the
same update
geode-core/src/distributedTest/java/org/apache/geode/cache/ConnectionPoolDUnitTest.java