@Test
  public void test028DynamicRegionCreation() {
    final String name = getName();

    final VM client1 = vm0;
    final VM srv1 = vm2;
    final VM srv2 = vm3;

    final String key1 = name + "-key1";
    final String value1 = name + "-val1";
    final String key2 = name + "-key2";
    final String value2 = name + "-val2";
    final String key3 = name + "-key3";
    final String value3 = name + "-val3";

    // setup servers
    Stream.of(srv1, srv2).forEach(vm -> vm.invoke("Create Cache Server", () -> {
      createDynamicRegionCache(null); // Creates a new DS and Cache
      assertThat(DynamicRegionFactory.get().isOpen()).isTrue();
      startBridgeServer(0);

      RegionFactory<Object, Object> factory = getCache().createRegionFactory();
      factory.setScope(Scope.DISTRIBUTED_ACK);
      factory.setDataPolicy(DataPolicy.REPLICATE);
      factory.setConcurrencyChecksEnabled(false);
      Region<Object, Object> region = createRootRegion(name, factory);
      region.put(key1, value1);
      assertThat(region.get(key1)).isEqualTo(value1);
    }));
    final String srv1Host = NetworkUtils.getServerHostName();
    final int srv1Port = srv1.invoke(ConnectionPoolDUnitTest::getCacheServerPort);

    final int srv2Port = srv2.invoke(ConnectionPoolDUnitTest::getCacheServerPort);

    // setup clients, do basic tests to make sure pool with notifier work as advertised
    client1.invoke("Create Cache Client", () -> {
      createLonerDS();
      AttributesFactory<Object, Object> factory = new AttributesFactory<>();
      factory.setConcurrencyChecksEnabled(false);
      Pool cp = configureConnectionPool(factory, srv1Host, new int[] {srv1Port,
          srv2Port}, true, -1, -1, null);
      assertThat(cp).isNotNull();

      {
        final PoolImpl pool = (PoolImpl) cp;

        await().untilAsserted(() -> {
          assertThat(pool.getPrimary()).isNotNull();
          assertThat(pool.getRedundants()).isNotEmpty();
        });

        assertThat(pool.getRedundants())
            .describedAs("backups=" + pool.getRedundants() + " expected=" + 1).isNotEmpty();
      }

      createDynamicRegionCache("testPool");

      assertThat(DynamicRegionFactory.get().isOpen()).isTrue();
      factory.setScope(Scope.LOCAL);
      factory.setConcurrencyChecksEnabled(false);
      factory.addCacheListener(new CertifiableTestCacheListener<>());
      Region<Object, Object> region = createRootRegion(name, factory.create());

      assertThat(region.getEntry(key1)).isNull();
      region.registerInterestRegex(".*", InterestResultPolicy.KEYS_VALUES); // this should match
      // the key
      assertThat(value1).isEqualTo(region.getEntry(key1).getValue()); // Update via registered
      // interest

      assertThat(region.getEntry(key2)).isNull();
      region.put(key2, value2); // use the Pool
      assertThat(value2).isEqualTo(region.getEntry(key2).getValue()); // Ensure that the notifier
      // didn't un-do the put, bug 35355

      region.put(key3, value3); // setup a key for invalidation from a notifier;
    });

    srv1.invoke("Validate Server1 update", () -> {
      CacheClientNotifier ccn = getInstance();
      final CacheClientNotifierStats ccnStats = ccn.getStats();
      final int eventCount = ccnStats.getEvents();
      Region<Object, Object> region = getRootRegion(name);
      assertThat(region).isNotNull();
      assertThat(value2)
          .isEqualTo(region.getEntry(key2).getValue()); // Validate the Pool worked,
      // getEntry works because of the mirror
      assertThat(value3).isEqualTo(region.getEntry(key3).getValue()); // Make sure we have the
      // other entry to use for notification
      region.put(key3, value1); // Change k3, sending some data to the client notifier

      // Wait for the update to propagate to the clients
      await("waiting for ccnStat").until(() -> ccnStats.getEvents() > eventCount);
    });

    srv2.invoke("Validate Server2 update", () -> {
      Region<Object, Object> rootRegion = getRootRegion(name);
      assertThat(rootRegion).isNotNull();
      assertThat(value2).isEqualTo(rootRegion.getEntry(key2).getValue()); // Validate the Pool
      // worked, getEntry works because of the mirror
      assertThat(value1).isEqualTo(rootRegion.getEntry(key3).getValue()); // From peer update;
    });

    client1.invoke("Validate Client notification", () -> {
      Region<Object, Object> rootRegion = getRootRegion(name);
      assertThat(rootRegion).isNotNull();
      CertifiableTestCacheListener<Object, Object> ctl =
          (CertifiableTestCacheListener<Object, Object>) rootRegion.getAttributes()
              .getCacheListeners()[0];
      ctl.waitForUpdated(key3);
      assertThat(value1).isEqualTo(rootRegion.getEntry(key3).getValue()); // Ensure that the
      // notifier updated the entry

    });
    // Ok, now we are ready to do some dynamic region action!
    final String v1Dynamic = value1 + "dynamic";
    final String dynFromClientName = name + "-dynamic-client";
    final String dynFromServerName = name + "-dynamic-server";
    client1.invoke("Client dynamic region creation", () -> {
      assertThat(DynamicRegionFactory.get().isOpen()).isTrue();
      Region<Object, Object> region = getRootRegion(name);
      assertThat(region).isNotNull();
      Region<Object, Object> dynamicRegion =
          DynamicRegionFactory.get().createDynamicRegion(name, dynFromClientName);
      assertThat(dynamicRegion.get(key1)).isNull(); // This should be enough to validate the
      // creation on the
      // server
      dynamicRegion.put(key1, v1Dynamic);
      assertThat(v1Dynamic).isEqualTo(dynamicRegion.getEntry(key1).getValue());
    });

    // Assert the servers have the dynamic region and the new value
    Stream.of(srv1, srv2)
        .forEach(vm -> vm.invoke("Validate dynamic region creation on server", () -> {
          Region<Object, Object> rootRegion = getRootRegion(name);
          assertThat(rootRegion).isNotNull();

          await().untilAsserted(() -> {
            Region<Object, Object> region = rootRegion.getSubregion(dynFromClientName);
            assertThat(region).isNotNull();
            assertThat(getCache().getRegion(name + SEPARATOR + dynFromClientName))
                .isNotNull();
          });

          Region<Object, Object> dynamicRegion = rootRegion.getSubregion(dynFromClientName);
          assertThat(v1Dynamic).isEqualTo(dynamicRegion.getEntry(key1).getValue());
        }));

    // now delete the dynamic region and see if it goes away on servers
    client1.invoke("Client dynamic region destruction", () -> {
      assertThat(DynamicRegionFactory.get().isActive()).isTrue();
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      String drName = r.getFullPath() + SEPARATOR + dynFromClientName;

      assertThat(getCache().getRegion(drName)).isNotNull();
      DynamicRegionFactory.get().destroyDynamicRegion(drName);
      assertThat(getCache().getRegion(drName)).isNull();
    });

    // Assert the servers no longer have the dynamic region

    Stream.of(srv1, srv2)
        .forEach(vm -> vm.invoke("Validate dynamic region destruction on server", () -> {
          Region<Object, Object> r = getRootRegion(name);
          assertThat(r).isNotNull();
          String drName = r.getFullPath() + SEPARATOR + dynFromClientName;
          assertThat(getCache().getRegion(drName)).isNull();
          try {
            DynamicRegionFactory.get().destroyDynamicRegion(drName);
            fail("expected RegionDestroyedException");
          } catch (RegionDestroyedException ignored) {
          }
        }));

    // Now try the reverse, create a dynamic region on the server and see if the client
    // has it
    srv2.invoke("Server dynamic region creation", () -> {
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      Region<Object, Object> dr =
          DynamicRegionFactory.get().createDynamicRegion(name, dynFromServerName);
      assertThat(dr.get(key1)).isNull();
      dr.put(key1, v1Dynamic);
      assertThat(v1Dynamic).isEqualTo(dr.getEntry(key1).getValue());
    });

    // Assert the servers have the dynamic region and the new value
    srv1.invoke("Validate dynamic region creation propagation to other server", () -> {
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      Region<Object, Object> dr = waitForSubRegion(r, dynFromServerName);
      assertThat(dr).isNotNull();
      assertThat(getCache().getRegion(name + SEPARATOR + dynFromServerName))
          .isNotNull();
      waitForEntry(dr, key1);
      assertThat(dr.getEntry(key1)).isNotNull();
      assertThat(v1Dynamic).isEqualTo(dr.getEntry(key1).getValue());
    });

    // Assert the clients have the dynamic region and the new value
    client1.invoke("Validate dynamic region creation on client", () -> {
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      Region<Object, Object> dr;

      await().pollInterval(1, SECONDS).until(() -> r.getSubregion(dynFromServerName) != null
          && getCache().getRegion(name + SEPARATOR + dynFromServerName) != null);

      dr = r.getSubregion(dynFromServerName);
      waitForEntry(dr, key1);
      assertThat(dr.getEntry(key1)).isNotNull();
      assertThat(v1Dynamic).isEqualTo(dr.getEntry(key1).getValue());
    });

    // now delete the dynamic region on a server and see if it goes away on client
    srv2.invoke("Server dynamic region destruction", () -> {
      assertThat(DynamicRegionFactory.get().isActive()).isTrue();
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      String drName = r.getFullPath() + SEPARATOR + dynFromServerName;

      assertThat(getCache().getRegion(drName)).isNotNull();
      DynamicRegionFactory.get().destroyDynamicRegion(drName);
      assertThat(getCache().getRegion(drName)).isNull();
    });

    srv1.invoke("Validate dynamic region destruction on other server", () -> {
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      String drName = r.getFullPath() + SEPARATOR + dynFromServerName;

      await().ignoreException(RegionDestroyedException.class)
          .until(() -> getCache().getRegion(drName) == null);
      assertThat(getCache().getRegion(drName)).isNull();
    });

    // Assert the clients no longer have the dynamic region
    client1.invoke("Validate dynamic region destruction on client", () -> {
      Region<Object, Object> r = getRootRegion(name);
      assertThat(r).isNotNull();
      String drName = r.getFullPath() + SEPARATOR + dynFromServerName;
      await().ignoreException(RegionDestroyedException.class)
          .until(() -> getCache().getRegion(drName) == null);

      Throwable thrown =
          catchThrowable(() -> DynamicRegionFactory.get().destroyDynamicRegion(drName));
      assertThat(thrown).isInstanceOf(RegionDestroyedException.class);
    });
  }
Test dynamic region creation instantiated from a bridge client causing regions to be created on
two different cache servers.
<p>
Also tests the reverse situation, a dynamic region is created on the cache server expecting the
same region to be created on the client.
<p>
Note: This test re-creates Distributed Systems for its own purposes and uses a Loner
distributed systems to isolate the Bridge Client.
geode-core/src/distributedTest/java/org/apache/geode/cache/ConnectionPoolDUnitTest.java