/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.geode.management;

import static java.lang.management.ManagementFactory.getPlatformMBeanServer;
import static java.util.Calendar.MONTH;
import static org.apache.geode.cache.EvictionAction.LOCAL_DESTROY;
import static org.apache.geode.cache.Region.SEPARATOR;
import static org.apache.geode.cache.RegionShortcut.LOCAL;
import static org.apache.geode.cache.RegionShortcut.PARTITION;
import static org.apache.geode.cache.RegionShortcut.PARTITION_REDUNDANT;
import static org.apache.geode.cache.RegionShortcut.REPLICATE;
import static org.apache.geode.distributed.ConfigurationProperties.ENABLE_TIME_STATISTICS;
import static org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_START;
import static org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLING_ENABLED;
import static org.apache.geode.management.internal.MBeanJMXAdapter.getDistributedRegionMbeanName;
import static org.apache.geode.management.internal.MBeanJMXAdapter.getMemberMBeanName;
import static org.apache.geode.management.internal.MBeanJMXAdapter.getRegionMBeanName;
import static org.apache.geode.test.awaitility.GeodeAwaitility.await;
import static org.apache.geode.test.dunit.Disconnect.disconnectAllFromDS;
import static org.apache.geode.test.dunit.Invoke.invokeInEveryVM;
import static org.apache.geode.test.dunit.VM.getVM;
import static org.apache.geode.test.dunit.VM.toArray;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;

import javax.management.InstanceNotFoundException;
import javax.management.MalformedObjectNameException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.EntryOperation;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.FixedPartitionAttributes;
import org.apache.geode.cache.FixedPartitionResolver;
import org.apache.geode.cache.PartitionAttributes;
import org.apache.geode.cache.PartitionAttributesFactory;
import org.apache.geode.cache.PartitionResolver;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.query.data.Portfolio;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.internal.cache.InternalCache;
import org.apache.geode.internal.cache.InternalRegion;
import org.apache.geode.internal.cache.TestObjectSizerImpl;
import org.apache.geode.internal.cache.eviction.EvictionCounters;
import org.apache.geode.management.internal.MBeanJMXAdapter;
import org.apache.geode.management.internal.SystemManagementService;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.rules.CacheRule;
import org.apache.geode.test.dunit.rules.DistributedRule;
import org.apache.geode.test.junit.rules.serializable.SerializableTestName;

/**
 * Distributed tests for {@link RegionMXBean}.
 *
 * <p>
 * This class checks and verifies various data and operations exposed through RegionMXBean
 * interface.
 *
 * <p>
 * Goal of the Test : RegionMBean gets created once region is created. Data like Region Attributes
 * data and stats are of proper value
 */
@SuppressWarnings("serial")
public class RegionManagementDUnitTest implements Serializable {

  private static final AtomicReference<List<Notification>> MEMBER_NOTIFICATIONS =
      new AtomicReference<>();
  private static final AtomicReference<List<Notification>> SYSTEM_NOTIFICATIONS =
      new AtomicReference<>();

  private String regionName;
  private String partitionedRegionName;
  private String subregionName;

  private VM managerVM;

  private VM[] memberVMs;

  @Rule
  public DistributedRule distributedRule = new DistributedRule();

  @Rule
  public CacheRule cacheRule = new CacheRule();

  @Rule
  public SerializableTestName testName = new SerializableTestName();

  @Before
  public void setUp() {
    String uniqueName = getClass().getSimpleName() + "_" + testName.getMethodName();
    regionName = uniqueName + "_region";
    partitionedRegionName = uniqueName + "_partitionedRegion";
    subregionName = uniqueName + "_subregion";

    managerVM = getVM(0);
    VM memberVM1 = getVM(1);
    VM memberVM2 = getVM(2);
    VM memberVM3 = getVM(3);

    memberVM1.invoke(() -> createMember(cacheRule));
    memberVM2.invoke(() -> createMember(cacheRule));
    memberVM3.invoke(() -> createMember(cacheRule));

    managerVM.invoke(() -> createManager(cacheRule));

    memberVMs = toArray(memberVM1, memberVM2, memberVM3);
  }

  @After
  public void tearDown() {
    disconnectAllFromDS();

    MEMBER_NOTIFICATIONS.set(null);
    SYSTEM_NOTIFICATIONS.set(null);
    invokeInEveryVM(() -> MEMBER_NOTIFICATIONS.set(null));
    invokeInEveryVM(() -> SYSTEM_NOTIFICATIONS.set(null));
  }

  /**
   * Tests all Region MBean related Management APIs:
   * <p>
   * a) Notification propagated to member MBean while a region is created<br>
   * b) Creates and check a Distributed Region
   */
  @Test
  public void testDistributedRegion() {
    // Adding notification listener for remote cache memberVMs
    managerVM.invoke(() -> addMemberNotificationListener(3));

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().createRegionFactory(REPLICATE).create(regionName);
        verifyReplicateRegionAfterCreate(regionName);
      });
    }

    managerVM.invoke(() -> verifyRemoteDistributedRegion(3, regionName));

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().getRegion(regionName).close();
        verifyReplicatedRegionAfterClose(regionName);
      });
    }

    managerVM.invoke(() -> verifyProxyCleanup(regionName));

    managerVM.invoke(() -> verifyMemberNotifications(regionName, 3));
  }

  /**
   * Tests all Region MBean related Management APIs:
   * <p>
   * a) Notification propagated to member MBean while a region is created<br>
   * b) Created and check a Partitioned Region
   */
  @Test
  public void testPartitionedRegion() {
    // Adding notification listener for remote cache memberVMs
    managerVM.invoke(() -> addMemberNotificationListener(3));

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().createRegionFactory(PARTITION_REDUNDANT).create(partitionedRegionName);
        verifyPartitionRegionAfterCreate(partitionedRegionName, false);
      });
    }

    managerVM.invoke(() -> verifyRemotePartitionRegion(partitionedRegionName));

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().getRegion(partitionedRegionName).close();
        verifyPartitionRegionAfterClose(partitionedRegionName);
      });
    }

    managerVM.invoke(() -> verifyMemberNotifications(partitionedRegionName, 3));
  }

  /**
   * Tests all Region MBean related Management APIs:
   * <p>
   * a) Notification propagated to member MBean while a region is created<br>
   * b) Creates and check a Fixed Partitioned Region
   */
  @Test
  public void testFixedPRRegionMBean() {
    // Adding notification listener for remote cache memberVMs
    managerVM.invoke(() -> addMemberNotificationListener(3));

    int primaryIndex = 0;
    for (VM memberVM : memberVMs) {
      List<FixedPartitionAttributes> fixedPartitionAttributesList =
          createFixedPartitionList(primaryIndex + 1);
      memberVM.invoke(
          () -> createFixedPartitionRegion(partitionedRegionName, fixedPartitionAttributesList));
      primaryIndex++;
    }

    managerVM.invoke(() -> verifyRemoteFixedPartitionRegion(partitionedRegionName));

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> getCache().getRegion(partitionedRegionName).close());
    }

    managerVM.invoke(() -> verifyMemberNotifications(partitionedRegionName, 3));
  }

  /**
   * Tests a Distributed Region at Managing Node side while region is created in a member node
   * asynchronously.
   */
  @Test
  public void testRegionAggregate() {
    // Adding notification listener for remote cache memberVMs
    managerVM.invoke(() -> addSystemNotificationListener());

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().createRegionFactory(REPLICATE).create(regionName);
      });
    }

    managerVM.invoke(() -> {
      verifyDistributedMBean(regionName, 3);
      getCache().createRegionFactory(REPLICATE).create(regionName);
      verifyDistributedMBean(regionName, 4);
    });

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> getCache().getRegion(regionName).close());
    }

    managerVM.invoke(() -> {
      verifyProxyCleanup(regionName);

      verifyDistributedMBean(regionName, 1);
      getCache().getRegion(regionName).close();
      verifyDistributedMBean(regionName, 0);

      // TODO: GEODE-1930: verifySystemNotifications is too flaky and needs to be fixed
      // verifySystemNotifications(regionName, 3);
    });
  }

  @Test
  public void testNavigationAPIS() {
    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().createRegionFactory(REPLICATE).create(regionName);
        getCache().createRegionFactory(PARTITION_REDUNDANT).create(partitionedRegionName);
      });
    }

    managerVM.invoke(() -> {
      getCache().createRegionFactory(REPLICATE).create(regionName);
      getCache().createRegionFactory(PARTITION_REDUNDANT).create(partitionedRegionName);
    });

    List<String> memberIds = new ArrayList<>();
    for (VM memberVM : memberVMs) {
      memberIds.add(
          memberVM.invoke(() -> getCache().getDistributedSystem().getDistributedMember().getId()));
    }

    managerVM.invoke(() -> verifyNavigationApis(memberIds));
  }

  @Test
  public void testSubRegions() {
    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        Region region = getCache().createRegionFactory(LOCAL).create(regionName);
        getCache().createRegionFactory(LOCAL).createSubregion(region, subregionName);
      });
    }

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> verifyRegionMXBeanIsNotNull(regionName, subregionName));
    }

    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> {
        getCache().getRegion(regionName).close();
        verifyRegionMXBeanIsNull(regionName, subregionName);
      });
    }
  }

  @Test
  public void testSpecialRegions() {
    memberVMs[0].invoke(() -> {
      RegionFactory<?, Portfolio> regionFactory = getCache().createRegionFactory(LOCAL);
      regionFactory.setValueConstraint(Portfolio.class);

      regionFactory.create("p-os");
      regionFactory.create("p_os");
    });

    managerVM.invoke(() -> {
      awaitDistributedRegionMXBean("p-os", 1);
      awaitDistributedRegionMXBean("p_os", 1);
    });
  }

  @Test
  public void testLruStats() {
    for (VM memberVM : memberVMs) {
      memberVM.invoke(() -> createDiskRegion(regionName));
    }

    managerVM.invoke(() -> verifyEntrySize(regionName, 3));
  }

  private InternalCache getCache() {
    return cacheRule.getCache();
  }

  private ManagementService getManagementService() {
    return ManagementService.getManagementService(cacheRule.getCache());
  }

  private SystemManagementService getSystemManagementService() {
    return (SystemManagementService) getManagementService();
  }

  private Set<DistributedMember> getOtherMembers() {
    Set<DistributedMember> allMembers =
        new HashSet<>(getCache().getDistributionManager().getNormalDistributionManagerIds());
    allMembers.remove(getCache().getDistributionManager().getId());
    return allMembers;
  }

  private String toPath(final String regionName) {
    return SEPARATOR + regionName;
  }

  private String toPath(final String regionName, final String subregionName) {
    return SEPARATOR + regionName + SEPARATOR + subregionName;
  }

  private void createDiskRegion(final String regionName) {
    EvictionAttributes evictionAttributes = EvictionAttributes.createLRUMemoryAttributes(20,
        new TestObjectSizerImpl(), LOCAL_DESTROY);

    RegionFactory<Integer, Object> regionFactory = getCache().createRegionFactory(LOCAL);
    regionFactory.setEvictionAttributes(evictionAttributes);

    Region<Integer, Object> region = regionFactory.create(regionName);

    EvictionCounters lruStats = ((InternalRegion) region).getEvictionController().getCounters();
    assertThat(lruStats).isNotNull();

    RegionMXBean regionMXBean = getManagementService().getLocalRegionMBean(toPath(regionName));
    assertThat(regionMXBean).isNotNull();

    for (int total = 0; total < 10; total++) {
      int[] array = new int[250];
      array[0] = total;
      region.put(total, array);
    }
    assertThat(regionMXBean.getEntrySize()).isGreaterThan(0);
  }

  private void createFixedPartitionRegion(final String regionName,
      final List<FixedPartitionAttributes> fixedPartitionAttributesList) {
    PartitionAttributesFactory<?, ?> partitionAttributesFactory = new PartitionAttributesFactory();
    partitionAttributesFactory.setRedundantCopies(2);
    partitionAttributesFactory.setTotalNumBuckets(12);

    for (FixedPartitionAttributes fixedPartitionAttributes : fixedPartitionAttributesList) {
      partitionAttributesFactory.addFixedPartitionAttributes(fixedPartitionAttributes);
    }

    partitionAttributesFactory.setPartitionResolver(new QuarterlyFixedPartitionResolver<>());

    RegionFactory<?, ?> regionFactory = getCache().createRegionFactory(PARTITION);
    regionFactory.setPartitionAttributes(partitionAttributesFactory.create());

    Region<?, ?> region = regionFactory.create(regionName);

    SystemManagementService service = getSystemManagementService();
    RegionMXBean regionMXBean = service.getLocalRegionMBean(toPath(regionName));
    RegionAttributes regionAttributes = region.getAttributes();

    PartitionAttributesData partitionAttributesData = regionMXBean.listPartitionAttributes();
    verifyPartitionData(regionAttributes, partitionAttributesData, true);

    FixedPartitionAttributesData[] fixedPartitionAttributesData =
        regionMXBean.listFixedPartitionAttributes();
    assertThat(fixedPartitionAttributesData).isNotNull();
    assertThat(fixedPartitionAttributesData).hasSize(3);

    for (FixedPartitionAttributesData aFixedPartitionAttributesData : fixedPartitionAttributesData) {
      // TODO: add real assertions for FixedPartitionAttributesData
      // LogWriterUtils.getLogWriter().info("<ExpectedString> Fixed PR Data is " +
      // fixedPartitionAttributesData[i] + "</ExpectedString> ");
    }
  }

  private List<FixedPartitionAttributes> createFixedPartitionList(final int primaryIndex) {
    List<FixedPartitionAttributes> fixedPartitionAttributesList = new ArrayList<>();
    if (primaryIndex == 1) {
      fixedPartitionAttributesList
          .add(FixedPartitionAttributes.createFixedPartition("Q1", true, 3));
      fixedPartitionAttributesList.add(FixedPartitionAttributes.createFixedPartition("Q2", 3));
      fixedPartitionAttributesList.add(FixedPartitionAttributes.createFixedPartition("Q3", 3));
    }
    if (primaryIndex == 2) {
      fixedPartitionAttributesList.add(FixedPartitionAttributes.createFixedPartition("Q1", 3));
      fixedPartitionAttributesList
          .add(FixedPartitionAttributes.createFixedPartition("Q2", true, 3));
      fixedPartitionAttributesList.add(FixedPartitionAttributes.createFixedPartition("Q3", 3));
    }
    if (primaryIndex == 3) {
      fixedPartitionAttributesList.add(FixedPartitionAttributes.createFixedPartition("Q1", 3));
      fixedPartitionAttributesList.add(FixedPartitionAttributes.createFixedPartition("Q2", 3));
      fixedPartitionAttributesList
          .add(FixedPartitionAttributes.createFixedPartition("Q3", true, 3));
    }
    return fixedPartitionAttributesList;
  }

  private void addMemberNotificationListener(final int expectedMembers)
      throws InstanceNotFoundException {
    Set<DistributedMember> otherMemberSet = getOtherMembers();
    assertThat(otherMemberSet).hasSize(expectedMembers);

    SystemManagementService service = getSystemManagementService();

    List<Notification> notifications = new ArrayList<>();
    MEMBER_NOTIFICATIONS.set(notifications);

    for (DistributedMember member : otherMemberSet) {
      MemberNotificationListener listener = new MemberNotificationListener(notifications);
      ObjectName objectName = service.getMemberMBeanName(member);
      awaitMemberMXBeanProxy(objectName);

      getPlatformMBeanServer().addNotificationListener(objectName, listener, null, null);
    }
  }

  /**
   * Add a Notification listener to DistributedSystemMBean which should gather all the notifications
   * which are propagated through all individual MemberMBeans Hence Region created/destroyed should
   * be visible to this listener
   */
  private void addSystemNotificationListener() throws InstanceNotFoundException {
    awaitDistributedSystemMXBean();

    List<Notification> notifications = new ArrayList<>();
    SYSTEM_NOTIFICATIONS.set(notifications);

    DistributedSystemNotificationListener listener =
        new DistributedSystemNotificationListener(notifications);
    ObjectName objectName = MBeanJMXAdapter.getDistributedSystemName();
    getPlatformMBeanServer().addNotificationListener(objectName, listener, null, null);
  }

  private void awaitMemberCount(final int expectedCount) {
    DistributedSystemMXBean distributedSystemMXBean = awaitDistributedSystemMXBean();
    await()
        .untilAsserted(
            () -> assertThat(distributedSystemMXBean.getMemberCount()).isEqualTo(expectedCount));
  }

  private DistributedRegionMXBean awaitDistributedRegionMXBean(final String regionName,
      final int memberCount) {
    SystemManagementService service = getSystemManagementService();

    await().untilAsserted(
        () -> assertThat(service.getDistributedRegionMXBean(toPath(regionName))).isNotNull());
    await()
        .untilAsserted(() -> assertThat(
            service.getDistributedRegionMXBean(toPath(regionName)).getMemberCount())
                .isEqualTo(memberCount));

    return service.getDistributedRegionMXBean(toPath(regionName));
  }

  private RegionMXBean awaitRegionMXBeanProxy(final DistributedMember member,
      final String regionName) {
    SystemManagementService service = getSystemManagementService();
    ObjectName objectName = service.getRegionMBeanName(member, toPath(regionName));
    String alias = "awaiting RegionMXBean proxy for " + member;

    await(alias)
        .untilAsserted(
            () -> assertThat(service.getMBeanProxy(objectName, RegionMXBean.class)).isNotNull());

    return service.getMBeanProxy(objectName, RegionMXBean.class);
  }

  private RegionMXBean awaitRegionMXBeanProxy(final ObjectName objectName) {
    SystemManagementService service = getSystemManagementService();

    await()
        .untilAsserted(
            () -> assertThat(service.getMBeanProxy(objectName, RegionMXBean.class)).isNotNull());

    return service.getMBeanProxy(objectName, RegionMXBean.class);
  }

  private MemberMXBean awaitMemberMXBeanProxy(final DistributedMember member) {
    SystemManagementService service = getSystemManagementService();
    ObjectName objectName = service.getMemberMBeanName(member);
    String alias = "awaiting MemberMXBean proxy for " + member;

    await(alias)
        .untilAsserted(
            () -> assertThat(service.getMBeanProxy(objectName, MemberMXBean.class)).isNotNull());

    return service.getMBeanProxy(objectName, MemberMXBean.class);
  }

  private MemberMXBean awaitMemberMXBeanProxy(final ObjectName objectName) {
    SystemManagementService service = getSystemManagementService();
    await()
        .untilAsserted(
            () -> assertThat(service.getMBeanProxy(objectName, MemberMXBean.class)).isNotNull());
    return service.getMBeanProxy(objectName, MemberMXBean.class);
  }

  private DistributedSystemMXBean awaitDistributedSystemMXBean() {
    ManagementService service = getSystemManagementService();

    await().untilAsserted(() -> assertThat(service.getDistributedSystemMXBean()).isNotNull());

    return service.getDistributedSystemMXBean();
  }

  private void verifyEntrySize(String regionName, final int expectedMembers) {
    DistributedRegionMXBean distributedRegionMXBean =
        awaitDistributedRegionMXBean(regionName, expectedMembers);
    assertThat(distributedRegionMXBean).isNotNull();
    assertThat(distributedRegionMXBean.getEntrySize()).isGreaterThan(0);
  }

  private void verifyRegionMXBeanIsNotNull(final String regionName, final String subregionName) {
    RegionMXBean regionMXBean =
        getManagementService().getLocalRegionMBean(toPath(regionName, subregionName));
    assertThat(regionMXBean).isNotNull();
  }

  private void verifyRegionMXBeanIsNull(final String regionName, final String subregionName) {
    RegionMXBean regionMXBean =
        getManagementService().getLocalRegionMBean(toPath(regionName, subregionName));
    assertThat(regionMXBean).isNull();
  }

  private void verifyNavigationApis(final List<String> memberIds) throws Exception {
    ManagementService service = getManagementService();
    assertThat(service.getDistributedSystemMXBean()).isNotNull();

    // With the DUnit framework there is a locator, a manager and 3 members
    awaitMemberCount(5);

    DistributedSystemMXBean distributedSystemMXBean = service.getDistributedSystemMXBean();
    assertThat(distributedSystemMXBean.listDistributedRegionObjectNames()).hasSize(2);

    assertThat(
        distributedSystemMXBean.fetchDistributedRegionObjectName(toPath(partitionedRegionName)))
            .isNotNull();
    assertThat(distributedSystemMXBean.fetchDistributedRegionObjectName(toPath(regionName)))
        .isNotNull();

    ObjectName actualName =
        distributedSystemMXBean.fetchDistributedRegionObjectName(toPath(partitionedRegionName));
    ObjectName expectedName = getDistributedRegionMbeanName(toPath(partitionedRegionName));
    assertThat(actualName).isEqualTo(expectedName);

    actualName = distributedSystemMXBean.fetchDistributedRegionObjectName(toPath(regionName));
    expectedName = getDistributedRegionMbeanName(toPath(regionName));
    assertThat(actualName).isEqualTo(expectedName);

    for (String memberId : memberIds) {
      ObjectName objectName = getMemberMBeanName(memberId);
      awaitMemberMXBeanProxy(objectName);

      ObjectName[] objectNames = distributedSystemMXBean.fetchRegionObjectNames(objectName);
      assertThat(objectNames).isNotNull();
      assertThat(objectNames).hasSize(2);

      List<ObjectName> listOfNames = Arrays.asList(objectNames);

      expectedName = getRegionMBeanName(memberId, toPath(partitionedRegionName));
      assertThat(listOfNames).contains(expectedName);

      expectedName = getRegionMBeanName(memberId, toPath(regionName));
      assertThat(listOfNames).contains(expectedName);
    }

    for (String memberId : memberIds) {
      ObjectName objectName = getMemberMBeanName(memberId);
      awaitMemberMXBeanProxy(objectName);

      expectedName = getRegionMBeanName(memberId, toPath(partitionedRegionName));
      awaitRegionMXBeanProxy(expectedName);

      actualName =
          distributedSystemMXBean.fetchRegionObjectName(memberId, toPath(partitionedRegionName));
      assertThat(actualName).isEqualTo(expectedName);

      expectedName = getRegionMBeanName(memberId, toPath(regionName));
      awaitRegionMXBeanProxy(expectedName);

      actualName = distributedSystemMXBean.fetchRegionObjectName(memberId, toPath(regionName));
      assertThat(actualName).isEqualTo(expectedName);
    }
  }

  private void verifyMemberNotifications(final String regionName, final int expectedMembers) {
    await()
        .untilAsserted(() -> assertThat(MEMBER_NOTIFICATIONS.get()).hasSize(expectedMembers * 2));

    int regionCreatedCount = 0;
    int regionDestroyedCount = 0;
    for (Notification notification : MEMBER_NOTIFICATIONS.get()) {
      if (JMXNotificationType.REGION_CREATED.equals(notification.getType())) {
        regionCreatedCount++;
        assertThat(notification.getMessage()).contains(regionName);
      } else if (JMXNotificationType.REGION_CLOSED.equals(notification.getType())) {
        regionDestroyedCount++;
        assertThat(notification.getMessage()).contains(regionName);
      } else {
        fail("Unexpected notification type: " + notification.getType());
      }
    }

    assertThat(regionCreatedCount).isEqualTo(expectedMembers);
    assertThat(regionDestroyedCount).isEqualTo(expectedMembers);

    // <[javax.management.Notification[source=10.118.33.232(17632)<v1>-32770][type=gemfire.distributedsystem.cache.region.created][message=Region
    // Created With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=10.118.33.232(17633)<v2>-32771][type=gemfire.distributedsystem.cache.region.created][message=Region
    // Created With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=10.118.33.232(17634)<v3>-32772][type=gemfire.distributedsystem.cache.region.created][message=Region
    // Created With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=10.118.33.232(17632)<v1>-32770][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=10.118.33.232(17633)<v2>-32771][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=10.118.33.232(17634)<v3>-32772][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION]]>
  }

  /**
   * Please don't delete verifySystemNotifications. We need to improve verification in this test
   * class and fix whatever flakiness is in this method.
   */
  @SuppressWarnings("unused")
  private void verifySystemNotifications(final String regionName, final int expectedMembers) {
    assertThat(SYSTEM_NOTIFICATIONS.get()).isNotNull();
    assertThat(SYSTEM_NOTIFICATIONS.get()).hasSize(expectedMembers + 2); // 2 for the manager


    int regionCreatedCount = 0;
    int regionDestroyedCount = 0;
    for (Notification notification : SYSTEM_NOTIFICATIONS.get()) {
      if (JMXNotificationType.REGION_CREATED.equals(notification.getType())) {
        regionCreatedCount++;
        assertThat(notification.getMessage()).contains(regionName);
      } else if (JMXNotificationType.REGION_CLOSED.equals(notification.getType())) {
        regionDestroyedCount++;
        assertThat(notification.getMessage()).contains(regionName);
      } else {
        fail("Unexpected notification type: " + notification.getType());
      }
    }

    assertThat(regionCreatedCount).isEqualTo(1); // just the manager
    assertThat(regionDestroyedCount).isEqualTo(expectedMembers + 1); // all 3 members + manager

    // <[javax.management.Notification[source=192.168.1.72(18496)<v27>-32770][type=gemfire.distributedsystem.cache.region.created][message=Region
    // Created With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=192.168.1.72(18497)<v28>-32771][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=192.168.1.72(18498)<v29>-32772][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=192.168.1.72(18499)<v30>-32773][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION],
    // javax.management.Notification[source=192.168.1.72(18496)<v27>-32770][type=gemfire.distributedsystem.cache.region.closed][message=Region
    // Destroyed/Closed With Name /MANAGEMENT_TEST_REGION]]>
  }

  private void verifyProxyCleanup(final String regionName) {
    SystemManagementService service = getSystemManagementService();

    Set<DistributedMember> otherMemberSet = getOtherMembers();
    for (DistributedMember member : otherMemberSet) {
      String alias = "Waiting for the proxy to get deleted at managing node";
      await(alias).untilAsserted(
          () -> assertThat(
              service.getMBeanProxy(service.getRegionMBeanName(member, toPath(regionName)),
                  RegionMXBean.class)).isNull());
    }
  }

  private void verifyRemoteDistributedRegion(final int expectedMembers, final String regionName) {
    Set<DistributedMember> otherMemberSet = getOtherMembers();
    assertThat(otherMemberSet).hasSize(expectedMembers);

    for (DistributedMember member : otherMemberSet) {
      RegionMXBean regionMXBean = awaitRegionMXBeanProxy(member, regionName);

      RegionAttributesData regionAttributesData = regionMXBean.listRegionAttributes();
      assertThat(regionAttributesData).isNotNull();

      MembershipAttributesData membershipAttributesData = regionMXBean.listMembershipAttributes();
      assertThat(membershipAttributesData).isNotNull();

      EvictionAttributesData evictionAttributesData = regionMXBean.listEvictionAttributes();
      assertThat(evictionAttributesData).isNotNull();
    }

    DistributedRegionMXBean distributedRegionMXBean =
        awaitDistributedRegionMXBean(regionName, expectedMembers);

    assertThat(distributedRegionMXBean).isNotNull();
    assertThat(distributedRegionMXBean.getFullPath()).isEqualTo(toPath(regionName));
  }

  private void verifyDistributedMBean(final String regionName, final int expectedMembers) {
    if (expectedMembers == 0) {
      ManagementService service = getManagementService();
      String alias = "Waiting for the proxy to get deleted at managing node";
      await(alias)
          .untilAsserted(
              () -> assertThat(service.getDistributedRegionMXBean(toPath(regionName))).isNull());
      return;
    }

    DistributedRegionMXBean distributedRegionMXBean =
        awaitDistributedRegionMXBean(regionName, expectedMembers);

    assertThat(distributedRegionMXBean.getFullPath()).isEqualTo(toPath(regionName));
    assertThat(distributedRegionMXBean.getMemberCount()).isEqualTo(expectedMembers);
    assertThat(distributedRegionMXBean.getMembers()).hasSize(expectedMembers);

    // Check Stats related Data
    // LogWriterUtils.getLogWriter().info("<ExpectedString> CacheListenerCallsAvgLatency is " +
    // distributedRegionMXBean.getCacheListenerCallsAvgLatency() + "</ExpectedString> ");
    // LogWriterUtils.getLogWriter().info("<ExpectedString> CacheWriterCallsAvgLatency is " +
    // distributedRegionMXBean.getCacheWriterCallsAvgLatency() + "</ExpectedString> ");
    // LogWriterUtils.getLogWriter().info("<ExpectedString> CreatesRate is " +
    // distributedRegionMXBean.getCreatesRate() + "</ExpectedString> ");
  }

  private void verifyRemotePartitionRegion(final String regionName) {
    Set<DistributedMember> otherMemberSet = getOtherMembers();

    for (DistributedMember member : otherMemberSet) {
      RegionMXBean regionMXBean = awaitRegionMXBeanProxy(member, regionName);
      PartitionAttributesData partitionAttributesData = regionMXBean.listPartitionAttributes();
      assertThat(partitionAttributesData).isNotNull();
    }

    ManagementService service = getManagementService();
    DistributedRegionMXBean distributedRegionMXBean =
        service.getDistributedRegionMXBean(toPath(regionName));
    assertThat(distributedRegionMXBean.getMembers()).hasSize(3);
  }

  private void verifyReplicateRegionAfterCreate(final String regionName)
      throws MalformedObjectNameException {
    Cache cache = getCache();

    String memberId =
        MBeanJMXAdapter
            .getMemberNameOrUniqueId(cache.getDistributedSystem().getDistributedMember());
    ObjectName objectName = ObjectName.getInstance("GemFire:type=Member,member=" + memberId);

    // List<Notification> notifications = new ArrayList<>();
    // MEMBER_NOTIFICATIONS_REF.set(notifications);
    //
    // MemberNotificationListener listener = new MemberNotificationListener(notifications);
    // ManagementFactory.getPlatformMBeanServer().addNotificationListener(objectName, listener,
    // null, null);

    SystemManagementService service = getSystemManagementService();
    RegionMXBean regionMXBean = service.getLocalRegionMBean(toPath(regionName));
    assertThat(regionMXBean).isNotNull();

    Region region = cache.getRegion(regionName);
    RegionAttributes regionAttributes = region.getAttributes();

    RegionAttributesData regionAttributesData = regionMXBean.listRegionAttributes();
    verifyRegionAttributes(regionAttributes, regionAttributesData);

    MembershipAttributesData membershipData = regionMXBean.listMembershipAttributes();
    assertThat(membershipData).isNotNull();

    EvictionAttributesData evictionData = regionMXBean.listEvictionAttributes();
    assertThat(evictionData).isNotNull();
  }

  private void verifyPartitionRegionAfterCreate(final String regionName,
      final boolean hasPartitionResolver) {
    Region region = getCache().getRegion(regionName);

    SystemManagementService service = getSystemManagementService();
    RegionMXBean regionMXBean = service.getLocalRegionMBean(toPath(regionName));

    verifyPartitionData(region.getAttributes(), regionMXBean.listPartitionAttributes(),
        hasPartitionResolver);
  }

  private void verifyReplicatedRegionAfterClose(final String regionName) {
    SystemManagementService service = getSystemManagementService();
    RegionMXBean regionMXBean = service.getLocalRegionMBean(toPath(regionName));
    assertThat(regionMXBean).isNull();

    ObjectName objectName = service.getRegionMBeanName(
        getCache().getDistributedSystem().getDistributedMember(), toPath(regionName));
    assertThat(service.getLocalManager().getManagementResourceRepo()
        .getEntryFromLocalMonitoringRegion(objectName)).isNull();
  }

  private void verifyPartitionRegionAfterClose(String regionName) {
    ManagementService service = getManagementService();
    RegionMXBean regionMXBean = service.getLocalRegionMBean(toPath(regionName));
    assertThat(regionMXBean).isNull();
  }

  private void verifyPartitionData(final RegionAttributes expectedRegionAttributes,
      final PartitionAttributesData partitionAttributesData,
      final boolean hasPartitionResolver) {
    PartitionAttributes expectedPartitionAttributes =
        expectedRegionAttributes.getPartitionAttributes();

    assertThat(partitionAttributesData.getRedundantCopies())
        .isEqualTo(expectedPartitionAttributes.getRedundantCopies());

    assertThat(partitionAttributesData.getTotalMaxMemory())
        .isEqualTo(expectedPartitionAttributes.getTotalMaxMemory());

    // Total number of buckets for whole region
    assertThat(partitionAttributesData.getTotalNumBuckets())
        .isEqualTo(expectedPartitionAttributes.getTotalNumBuckets());

    assertThat(partitionAttributesData.getLocalMaxMemory())
        .isEqualTo(expectedPartitionAttributes.getLocalMaxMemory());

    assertThat(partitionAttributesData.getColocatedWith())
        .isEqualTo(expectedPartitionAttributes.getColocatedWith());

    if (hasPartitionResolver) {
      PartitionResolver partitionResolver = expectedPartitionAttributes.getPartitionResolver();
      assertThat(partitionAttributesData.getPartitionResolver())
          .isEqualTo(partitionResolver.getName());

    } else {

      assertThat(partitionAttributesData.getPartitionResolver()).isNull();
    }

    assertThat(partitionAttributesData.getRecoveryDelay())
        .isEqualTo(expectedPartitionAttributes.getRecoveryDelay());

    assertThat(partitionAttributesData.getStartupRecoveryDelay())
        .isEqualTo(expectedPartitionAttributes.getStartupRecoveryDelay());

    if (expectedPartitionAttributes.getPartitionListeners() != null) {
      for (int i = 0; i < expectedPartitionAttributes.getPartitionListeners().length; i++) {
        // assertEquals((expectedPartitionAttributes.getPartitionListeners())[i].getClass().getCanonicalName(),
        // partitionAttributesData.getPartitionListeners()[i]);
        assertThat(partitionAttributesData.getPartitionListeners()[i]).isEqualTo(
            expectedPartitionAttributes.getPartitionListeners()[i].getClass().getCanonicalName());
      }
    }
  }

  private void verifyRegionAttributes(final RegionAttributes regionAttributes,
      final RegionAttributesData regionAttributesData) {
    assertThat(regionAttributesData.getCompressorClassName()).isNull();

    String cacheLoaderClassName = null;
    if (regionAttributes.getCacheLoader() != null) {
      cacheLoaderClassName = regionAttributes.getCacheLoader().getClass().getCanonicalName();
    }
    assertThat(regionAttributesData.getCacheLoaderClassName()).isEqualTo(cacheLoaderClassName);

    String cacheWriteClassName = null;
    if (regionAttributes.getCacheWriter() != null) {
      cacheWriteClassName = regionAttributes.getCacheWriter().getClass().getCanonicalName();
    }
    assertThat(regionAttributesData.getCacheWriterClassName()).isEqualTo(cacheWriteClassName);

    String keyConstraintClassName = null;
    if (regionAttributes.getKeyConstraint() != null) {
      keyConstraintClassName = regionAttributes.getKeyConstraint().getName();
    }
    assertThat(regionAttributesData.getKeyConstraintClassName()).isEqualTo(keyConstraintClassName);

    String valueContstaintClassName = null;
    if (regionAttributes.getValueConstraint() != null) {
      valueContstaintClassName = regionAttributes.getValueConstraint().getName();
    }
    assertThat(regionAttributesData.getValueConstraintClassName())
        .isEqualTo(valueContstaintClassName);

    CacheListener[] listeners = regionAttributes.getCacheListeners();
    if (listeners != null) {
      String[] value = regionAttributesData.getCacheListeners();
      for (int i = 0; i < listeners.length; i++) {
        assertThat(listeners[i].getClass().getName()).isEqualTo(value[i]);
      }
    }

    assertThat(regionAttributesData.getRegionTimeToLive())
        .isEqualTo(regionAttributes.getRegionTimeToLive().getTimeout());

    assertThat(regionAttributesData.getRegionIdleTimeout())
        .isEqualTo(regionAttributes.getRegionIdleTimeout().getTimeout());

    assertThat(regionAttributesData.getEntryTimeToLive())
        .isEqualTo(regionAttributes.getEntryTimeToLive().getTimeout());

    assertThat(regionAttributesData.getEntryIdleTimeout())
        .isEqualTo(regionAttributes.getEntryIdleTimeout().getTimeout());

    String customEntryTimeToLive = null;
    Object o1 = regionAttributes.getCustomEntryTimeToLive();
    if (o1 != null) {
      customEntryTimeToLive = o1.toString();
    }
    assertThat(regionAttributesData.getCustomEntryTimeToLive()).isEqualTo(customEntryTimeToLive);

    String customEntryIdleTimeout = null;
    Object o2 = regionAttributes.getCustomEntryIdleTimeout();
    if (o2 != null) {
      customEntryIdleTimeout = o2.toString();
    }
    assertThat(regionAttributesData.getCustomEntryIdleTimeout()).isEqualTo(customEntryIdleTimeout);

    assertThat(regionAttributesData.isIgnoreJTA()).isEqualTo(regionAttributes.getIgnoreJTA());

    assertThat(regionAttributesData.getDataPolicy())
        .isEqualTo(regionAttributes.getDataPolicy().toString());

    assertThat(regionAttributesData.getScope()).isEqualTo(regionAttributes.getScope().toString());

    assertThat(regionAttributesData.getInitialCapacity())
        .isEqualTo(regionAttributes.getInitialCapacity());

    assertThat(regionAttributesData.getLoadFactor()).isEqualTo(regionAttributes.getLoadFactor());

    assertThat(regionAttributesData.isLockGrantor()).isEqualTo(regionAttributes.isLockGrantor());

    assertThat(regionAttributesData.isMulticastEnabled())
        .isEqualTo(regionAttributes.getMulticastEnabled());

    assertThat(regionAttributesData.getConcurrencyLevel())
        .isEqualTo(regionAttributes.getConcurrencyLevel());

    assertThat(regionAttributesData.isIndexMaintenanceSynchronous())
        .isEqualTo(regionAttributes.getIndexMaintenanceSynchronous());

    assertThat(regionAttributesData.isStatisticsEnabled())
        .isEqualTo(regionAttributes.getStatisticsEnabled());

    assertThat(regionAttributesData.isSubscriptionConflationEnabled())
        .isEqualTo(regionAttributes.getEnableSubscriptionConflation());

    assertThat(regionAttributesData.isAsyncConflationEnabled())
        .isEqualTo(regionAttributes.getEnableAsyncConflation());

    assertThat(regionAttributesData.getPoolName()).isEqualTo(regionAttributes.getPoolName());

    assertThat(regionAttributesData.isCloningEnabled())
        .isEqualTo(regionAttributes.getCloningEnabled());

    assertThat(regionAttributesData.getDiskStoreName())
        .isEqualTo(regionAttributes.getDiskStoreName());

    String interestPolicy = null;
    if (regionAttributes.getSubscriptionAttributes() != null) {
      interestPolicy = regionAttributes.getSubscriptionAttributes().getInterestPolicy().toString();
    }
    assertThat(regionAttributesData.getInterestPolicy()).isEqualTo(interestPolicy);

    assertThat(regionAttributesData.isDiskSynchronous())
        .isEqualTo(regionAttributes.isDiskSynchronous());
  }

  private void verifyRemoteFixedPartitionRegion(final String regionName) {
    Set<DistributedMember> otherMemberSet = getOtherMembers();

    for (DistributedMember member : otherMemberSet) {
      RegionMXBean bean = awaitRegionMXBeanProxy(member, regionName);

      PartitionAttributesData data = bean.listPartitionAttributes();
      assertThat(data).isNotNull();

      FixedPartitionAttributesData[] fixedPrData = bean.listFixedPartitionAttributes();
      assertThat(fixedPrData).isNotNull();
      assertThat(fixedPrData).hasSize(3);

      for (FixedPartitionAttributesData aFixedPrData : fixedPrData) {
        // TODO: add real assertions for FixedPartitionAttributesData
        // LogWriterUtils.getLogWriter().info("<ExpectedString> Remote PR Data is " +
        // fixedPrData[i] + "</ExpectedString> ");
      }
    }
  }

  private static void createManager(CacheRule cacheRule) {
    Properties config = new Properties();
    config.put(JMX_MANAGER, "true");
    config.put(JMX_MANAGER_START, "true");
    config.put(JMX_MANAGER_PORT, "0");
    config.put(HTTP_SERVICE_PORT, "0");
    config.put(ENABLE_TIME_STATISTICS, "true");
    config.put(STATISTIC_SAMPLING_ENABLED, "true");

    cacheRule.createCache(config);
  }

  private static void createMember(CacheRule cacheRule) {
    Properties config = new Properties();
    config.put(JMX_MANAGER, "false");
    config.put(ENABLE_TIME_STATISTICS, "true");
    config.put(STATISTIC_SAMPLING_ENABLED, "true");

    cacheRule.createCache(config);
  }

  /**
   * Registered in manager VM. Listens to notifications from a MemberMXBean.
   */
  private static class MemberNotificationListener implements NotificationListener {

    private final List<Notification> notifications;

    private MemberNotificationListener(List<Notification> notifications) {
      this.notifications = notifications;
    }

    @Override
    public void handleNotification(final Notification notification, final Object handback) {
      assertThat(notification).isNotNull();

      assertThat(JMXNotificationType.REGION_CREATED.equals(notification.getType())
          || JMXNotificationType.REGION_CLOSED.equals(notification.getType())).isTrue();

      notifications.add(notification);

      // TODO: add real assertions for Notifications
      // LogWriterUtils.getLogWriter().info("<ExpectedString> Member Level Notifications" +
      // notification + "</ExpectedString> ");
    }
  }

  /**
   * Registered in manager VM. Listens to notifications from a DistributedSystemMXBean.
   */
  private static class DistributedSystemNotificationListener implements NotificationListener {

    private final List<Notification> notifications;

    private DistributedSystemNotificationListener(List<Notification> notifications) {
      this.notifications = notifications;
    }

    @Override
    public void handleNotification(final Notification notification, final Object handback) {
      assertThat(notification).isNotNull();

      notifications.add(notification);

      // TODO: add real assertions for Notifications
      // LogWriterUtils.getLogWriter().info("<ExpectedString> Distributed System Notifications" +
      // notification + "</ExpectedString> ");
    }
  }

  /**
   * Routes based on which quarter of the year that a month falls within.
   */
  private static class QuarterlyFixedPartitionResolver<K, V>
      implements FixedPartitionResolver<K, V> {

    @Override
    public String getPartitionName(EntryOperation<K, V> opDetails,
        @Deprecated Set<String> targetPartitions) {
      int month = getMonth(opDetails);

      if (month == 0 || month == 1 || month == 2) {
        return "Q1";
      } else if (month == 3 || month == 4 || month == 5) {
        return "Q2";
      } else if (month == 6 || month == 7 || month == 8) {
        return "Q3";
      } else if (month == 9 || month == 10 || month == 11) {
        return "Q4";
      } else {
        return "Invalid Quarter";
      }
    }

    @Override
    public Serializable getRoutingObject(EntryOperation<K, V> opDetails) {
      int month = getMonth(opDetails);

      switch (month) {
        case 0:
          return "January";
        case 1:
          return "February";
        case 2:
          return "March";
        case 3:
          return "April";
        case 4:
          return "May";
        case 5:
          return "June";
        case 6:
          return "July";
        case 7:
          return "August";
        case 8:
          return "September";
        case 9:
          return "October";
        case 10:
          return "November";
        case 11:
          return "December";
        default:
          return null;
      }
    }

    @Override
    public String getName() {
      return getClass().getSimpleName();
    }

    private int getMonth(EntryOperation<K, V> opDetails) {
      Date date = (Date) opDetails.getKey();
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(date);
      return calendar.get(MONTH);
    }
  }
}
