@Test
  public void testEnforceZoneWithMultipleRegions() {
    VM vm0 = getVM(0);
    VM vm1 = getVM(1);
    VM vm2 = getVM(2);

    vm0.invoke(() -> setRedundancyZone("A"));
    vm1.invoke(() -> setRedundancyZone("A"));

    DistributedMember zoneBMember = vm2.invoke(() -> {
      setRedundancyZone("B");
      return getCache().getDistributedSystem().getDistributedMember();
    });

    vm0.invoke(() -> InternalResourceManager.setResourceObserver(new ParallelRecoveryObserver(2)));

    // Create the region in only 1 VM
    vm0.invoke(this::createTwoRegionsWithParallelRecoveryObserver);

    // Create some buckets
    vm0.invoke(() -> {
      doPuts("region1");
      doPuts("region2");
    });

    // make sure we can tell that the buckets have low redundancy
    vm0.invoke(() -> validateRedundancyOfTwoRegions("region1", "region2", 6, 0, 6));

    // Create the region in the other VMs (should have no effect)
    for (VM vm : toArray(vm1, vm2)) {
      vm.invoke(() -> {
        InternalResourceManager.setResourceObserver(new ParallelRecoveryObserver(2));
        createTwoRegionsWithParallelRecoveryObserver();
      });
    }

    // Make sure we still have low redundancy
    vm0.invoke(() -> validateRedundancyOfTwoRegions("region1", "region2", 6, 0, 6));

    // Now do a rebalance
    vm0.invoke(() -> {
      InternalResourceManager manager = getCache().getInternalResourceManager();
      RebalanceResults results = doRebalance(false, manager);

      // We expect to satisfy redundancy with the zone B member
      assertThat(results.getTotalBucketCreatesCompleted()).isEqualTo(12);

      // 2 primaries will go to vm2, leaving vm0 and vm1 with 2 primaries each
      assertThat(results.getTotalPrimaryTransfersCompleted()).isEqualTo(4);

      // We actually *will* transfer 3 buckets to the other member in zone A, because that
      // improves the balance
      assertThat(results.getTotalBucketTransfersCompleted()).isEqualTo(6);

      Set<PartitionRebalanceInfo> detailSet = results.getPartitionRebalanceDetails();
      assertThat(detailSet).hasSize(2);

      for (PartitionRebalanceInfo details : detailSet) {
        assertThat(details.getBucketCreatesCompleted()).isEqualTo(6);
        assertThat(details.getPrimaryTransfersCompleted()).isEqualTo(2);
        assertThat(details.getBucketTransfersCompleted()).isEqualTo(3);

        Set<PartitionMemberInfo> afterDetails = details.getPartitionMemberDetailsAfter();
        for (PartitionMemberInfo info : afterDetails) {
          if (info.getDistributedMember().equals(zoneBMember)) {
            assertThat(info.getBucketCount()).isEqualTo(6);
          } else {
            assertThat(info.getBucketCount()).isEqualTo(3);
          }
          assertThat(info.getPrimaryCount()).isEqualTo(2);
        }
      }

      validateStatistics(manager, results);
    });

    vm0.invoke(() -> {
      assertThat(((ParallelRecoveryObserver) InternalResourceManager.getResourceObserver())
          .isObserverCalled()).isTrue();
    });

    vm0.invoke(() -> validateBucketCount("region1", 3));
    vm1.invoke(() -> validateBucketCount("region1", 3));
    vm2.invoke(() -> validateBucketCount("region1", 6));

    vm0.invoke(() -> validateBucketCount("region2", 3));
    vm1.invoke(() -> validateBucketCount("region2", 3));
    vm2.invoke(() -> validateBucketCount("region2", 6));
  }
Test that we correctly use the redundancy-zone property to determine where to place redundant
copies of a buckets.
geode-core/src/distributedTest/java/org/apache/geode/internal/cache/control/RebalanceOperationDistributedTest.java