/*
 * 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 org.apache.geode.distributed.ConfigurationProperties.LOG_FILE;
import static org.apache.geode.distributed.ConfigurationProperties.REDUNDANCY_ZONE;
import static org.assertj.core.api.Assertions.assertThat;

import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.management.JMException;
import javax.management.Notification;
import javax.management.NotificationListener;
import javax.management.ObjectName;

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

import org.apache.geode.cache.Cache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionFactory;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.InternalDistributedSystem;
import org.apache.geode.distributed.internal.membership.InternalDistributedMember;
import org.apache.geode.management.internal.LocalManager;
import org.apache.geode.management.internal.MBeanJMXAdapter;
import org.apache.geode.management.internal.ManagementConstants;
import org.apache.geode.management.internal.NotificationHub.NotificationHubListener;
import org.apache.geode.management.internal.SystemManagementService;
import org.apache.geode.test.awaitility.GeodeAwaitility;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.junit.rules.serializable.SerializableTemporaryFolder;
import org.apache.geode.test.junit.rules.serializable.SerializableTestName;

/**
 * Distributed tests for {@link MemberMXBean}.
 * <p>
 *
 * This class checks and verifies various data and operations exposed through MemberMXBean
 * interface.
 * <p>
 *
 * Goal of the Test : MemberMBean gets created once cache is created. Data like config data and
 * stats are of proper value To check proper federation of MemberMBean including remote ops and
 * remote data access
 */

@SuppressWarnings({"serial", "unused"})
public class CacheManagementDUnitTest implements Serializable {

  /** used in memberVMs */
  private static final String NOTIFICATION_REGION_NAME = "NotifTestRegion_";

  /** used in managerVM */
  private static final List<Notification> notifications = new ArrayList<>();

  @Manager
  private VM managerVM;

  @Member
  private VM[] memberVMs;

  @Rule
  public ManagementTestRule managementTestRule = ManagementTestRule.builder().build();

  @Rule
  public SerializableTemporaryFolder temporaryFolder = new SerializableTemporaryFolder();

  @Rule
  public SerializableTestName testName = new SerializableTestName();

  @Before
  public void before() throws Exception {
    this.managerVM.invoke(() -> notifications.clear());
  }

  @Test
  public void testGemFireConfigData() throws Exception {
    this.managementTestRule.createMembers();
    this.managementTestRule.createManagers();

    Map<DistributedMember, DistributionConfig> configMap = new HashMap<>();
    for (VM memberVM : this.memberVMs) {
      Map<DistributedMember, DistributionConfig> configMapMember =
          memberVM.invoke(() -> verifyConfigData());
      configMap.putAll(configMapMember);
    }

    this.managerVM.invoke(() -> verifyConfigDataRemote(configMap));
  }

  /**
   * Tests each and every operations that is defined on the MemberMXBean
   */
  @Test
  public void testMemberMBeanOperations() throws Exception {
    int i = 1;
    for (VM memberVM : this.memberVMs) {
      Properties props = new Properties();
      props.setProperty(LOG_FILE, this.temporaryFolder
          .newFile(this.testName.getMethodName() + "-VM" + i + ".log").getAbsolutePath());
      this.managementTestRule.createMember(memberVM, props);
      i++;
    }

    this.managementTestRule.createManagers();

    for (VM memberVM : this.memberVMs) {
      String logMessage = "This line should be in the log";
      memberVM.invoke(() -> this.managementTestRule.getCache().getLogger().info(logMessage));

      String log = memberVM.invoke(() -> fetchLog(30));
      assertThat(log).isNotNull();
      assertThat(log).contains(logMessage);

      JVMMetrics jvmMetrics = memberVM.invoke(() -> fetchJVMMetrics());

      OSMetrics osMetrics = memberVM.invoke(() -> fetchOSMetrics());

      // TODO: need assertions

      memberVM.invoke(() -> shutDownMember());
    }

    this.managerVM.invoke(() -> verifyExpectedMembers(0));
  }

  /**
   * Invoke remote operations on MemberMBean
   */
  @Test
  public void testMemberMBeanOpsRemote() throws Exception {
    this.managementTestRule.createMembers();
    this.managementTestRule.createManagers();
    this.managerVM.invoke(() -> invokeRemoteMemberMXBeanOps());
  }

  /**
   * Creates and starts a managerVM. Multiple Managers
   */
  @Test
  public void testManager() throws Exception {
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);

    this.managementTestRule.createManager(this.memberVMs[2], false);

    this.managementTestRule.createManager(this.managerVM, false);

    this.memberVMs[2].invoke(() -> startManager());

    // Now start Managing node managerVM. System will have two Managers now which
    // should be OK
    DistributedMember member = this.managementTestRule.getDistributedMember(this.memberVMs[2]);
    this.managementTestRule.startManager(this.managerVM);

    verifyManagerStarted(this.managerVM, member);
    this.managementTestRule.stopManager(this.managerVM);
  }

  /**
   * Creates and starts a managerVM. Multiple Managers
   */
  @Test
  public void testManagerShutdown() throws Exception {
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);
    this.managementTestRule.createMember(this.memberVMs[2]);

    this.managementTestRule.createManager(this.managerVM, false);
    this.managementTestRule.startManager(this.managerVM);

    verifyManagerStarted(this.managerVM,
        this.managementTestRule.getDistributedMember(this.memberVMs[0]));

    this.managementTestRule.stopManager(this.managerVM);
    verifyManagerStopped(this.managerVM, this.memberVMs.length);
  }

  @Test
  public void closeCacheShouldStopLocalManager() throws Exception {
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);

    this.managementTestRule.createManager(this.memberVMs[2], false);

    // Only creates a cache in Managing Node
    // Does not start the managerVM
    this.managementTestRule.createManager(this.managerVM, false);

    this.memberVMs[2].invoke(() -> startManager());

    this.memberVMs[2].invoke(() -> {
      SystemManagementService service = this.managementTestRule.getSystemManagementService();
      LocalManager localManager = service.getLocalManager();
      this.managementTestRule.getCache().close();
      assertThat(localManager.isRunning()).isFalse();
      assertThat(service.isManager()).isFalse();
      assertThat(service.getLocalManager()).isNull();
    });
  }

  @Test
  public void testGetMBean() throws Exception {
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);
    this.managementTestRule.createMember(this.memberVMs[2]);

    this.managementTestRule.createManager(this.managerVM, false);

    this.managementTestRule.startManager(this.managerVM);

    verifyGetMBeanInstance(this.managerVM);
  }

  @Test
  public void testQueryMBeans() throws Exception {
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);
    this.managementTestRule.createMember(this.memberVMs[2]);

    this.managementTestRule.createManager(this.managerVM, false);

    this.managementTestRule.startManager(this.managerVM);

    verifyQueryMBeans(this.managerVM);
  }

  @Test
  public void testNotification() throws Exception {
    // Step : 1 : Create Managed Node Caches
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);
    this.managementTestRule.createMember(this.memberVMs[2]);

    // Step : 2 : Create Managing Node Cache, start managerVM, add a notification
    // handler to DistributedSystemMXBean
    this.managementTestRule.createManager(this.managerVM, false);
    this.managementTestRule.startManager(this.managerVM);
    attachListenerToDistributedSystemMXBean(this.managerVM);

    // Step : 3 : Verify Notification count, notification region sizes
    verifyNotificationsAndRegionSize(this.memberVMs[0], this.memberVMs[1], this.memberVMs[2],
        this.managerVM);
  }

  @Test
  public void testNotificationManagingNodeFirst() throws Exception {
    // Step : 1 : Create Managing Node Cache, start managerVM, add a notification
    // handler to DistributedSystemMXBean
    this.managementTestRule.createManager(this.managerVM, false);
    this.managementTestRule.startManager(this.managerVM);

    attachListenerToDistributedSystemMXBean(this.managerVM);

    // Step : 2 : Create Managed Node Caches
    this.managementTestRule.createMember(this.memberVMs[0]);
    this.managementTestRule.createMember(this.memberVMs[1]);
    this.managementTestRule.createMember(this.memberVMs[2]);

    // Step : 3 : Verify Notification count, notification region sizes
    verifyNotificationsAndRegionSize(this.memberVMs[0], this.memberVMs[1], this.memberVMs[2],
        this.managerVM);
  }

  @Test
  public void testRedundancyZone() throws Exception {
    String redundancyZone = "ARMY_ZONE";

    Properties props = new Properties();
    props.setProperty(REDUNDANCY_ZONE, redundancyZone);

    this.managementTestRule.createMember(this.memberVMs[0], props);

    this.memberVMs[0].invoke("verifyRedundancyZone", () -> {
      ManagementService service = this.managementTestRule.getExistingManagementService();
      MemberMXBean memberMXBean = service.getMemberMXBean();
      assertThat(memberMXBean.getRedundancyZone()).isEqualTo(redundancyZone);
    });
  }

  private void verifyQueryMBeans(final VM managerVM) {
    managerVM.invoke("validateQueryMBeans", () -> {
      SystemManagementService service = this.managementTestRule.getSystemManagementService();
      Set<DistributedMember> otherMembers = this.managementTestRule.getOtherNormalMembers();
      Set<ObjectName> superSet = new HashSet<>();

      for (DistributedMember member : otherMembers) {
        ObjectName memberMBeanName = service.getMemberMBeanName(member);

        MXBeanAwaitility.awaitMemberMXBeanProxy(member, service);

        Set<ObjectName> objectNames = service.queryMBeanNames(member);
        superSet.addAll(objectNames);
        assertThat(objectNames.contains(memberMBeanName)).isTrue();
      }

      Set<ObjectName> names =
          service.queryMBeanNames(this.managementTestRule.getDistributedMember());
      ObjectName[] arrayOfNames = names.toArray(new ObjectName[names.size()]);

      assertThat(superSet).doesNotContain(arrayOfNames); // TODO: what value does this assertion
                                                         // have?
    });
  }

  private void verifyGetMBeanInstance(final VM managerVM) {
    managerVM.invoke("verifyGetMBeanInstance", () -> {
      SystemManagementService service = this.managementTestRule.getSystemManagementService();
      Set<DistributedMember> otherMembers = this.managementTestRule.getOtherNormalMembers();

      for (DistributedMember member : otherMembers) {
        ObjectName memberMBeanName = service.getMemberMBeanName(member);

        MXBeanAwaitility.awaitMemberMXBeanProxy(member, service);

        MemberMXBean memberMXBean = service.getMBeanInstance(memberMBeanName, MemberMXBean.class);
        assertThat(memberMXBean).isNotNull();
      }

      DistributedMember distributedMember = this.managementTestRule.getDistributedMember();
      ObjectName memberMBeanName = service.getMemberMBeanName(distributedMember);
      MemberMXBean memberMXBean = service.getMBeanInstance(memberMBeanName, MemberMXBean.class);
      assertThat(memberMXBean).isNotNull();
    });
  }

  private void verifyManagerStarted(final VM managerVM, final DistributedMember otherMember) {
    managerVM.invoke("verifyManagerStarted", () -> {
      SystemManagementService service = this.managementTestRule.getSystemManagementService();
      assertThat(service.isManager()).isTrue();

      assertThat(service.getLocalManager().isRunning()).isTrue();

      assertThat(service.getLocalManager().getFederationScheduler().isShutdown()).isFalse();

      ObjectName memberMBeanName = service.getMemberMBeanName(otherMember);

      GeodeAwaitility.await().untilAsserted(
          () -> assertThat(service.getMBeanProxy(memberMBeanName, MemberMXBean.class)).isNotNull());
      MemberMXBean memberMXBean = service.getMBeanProxy(memberMBeanName, MemberMXBean.class);

      // Ensure Data getting federated from Managing node
      long start = memberMXBean.getMemberUpTime();
      GeodeAwaitility.await()
          .untilAsserted(() -> assertThat(memberMXBean.getMemberUpTime()).isGreaterThan(start));
    });
  }

  /**
   * Add any Manager clean up asserts here
   */
  private void verifyManagerStopped(final VM managerVM, final int otherMembersCount) {
    managerVM.invoke("verifyManagerStopped", () -> {
      SystemManagementService service = this.managementTestRule.getSystemManagementService();

      assertThat(service.isManager()).isFalse();
      assertThat(service.getLocalManager().isRunning()).isTrue();
      assertThat(service.getLocalManager().getFederationScheduler().isShutdown()).isFalse();

      // Check for Proxies
      Set<DistributedMember> otherMembers = this.managementTestRule.getOtherNormalMembers();
      assertThat(otherMembers).hasSize(otherMembersCount);

      for (DistributedMember member : otherMembers) {
        Set<ObjectName> proxyNames =
            service.getFederatingManager().getProxyFactory().findAllProxies(member);
        assertThat(proxyNames).isEmpty();

        ObjectName proxyMBeanName = service.getMemberMBeanName(member);
        assertThat(MBeanJMXAdapter.mbeanServer.isRegistered(proxyMBeanName)).isFalse();
      }
    });
  }

  private Map<DistributedMember, DistributionConfig> verifyConfigData() {
    ManagementService service = this.managementTestRule.getManagementService();
    InternalDistributedSystem ids =
        (InternalDistributedSystem) this.managementTestRule.getCache().getDistributedSystem();
    DistributionConfig config = ids.getConfig();

    MemberMXBean bean = service.getMemberMXBean();
    GemFireProperties data = bean.listGemFireProperties();
    verifyGemFirePropertiesData(config, data);

    Map<DistributedMember, DistributionConfig> configMap = new HashMap<>();
    configMap.put(ids.getDistributedMember(), config);
    return configMap;
  }

  /**
   * This is to check whether the config data has been propagated to the Managing node properly or
   * not.
   */
  private void verifyConfigDataRemote(final Map<DistributedMember, DistributionConfig> configMap) {
    SystemManagementService service = this.managementTestRule.getSystemManagementService();
    Set<DistributedMember> otherMembers = this.managementTestRule.getOtherNormalMembers();

    for (DistributedMember member : otherMembers) {
      MemberMXBean memberMXBean = MXBeanAwaitility.awaitMemberMXBeanProxy(member, service);

      GemFireProperties data = memberMXBean.listGemFireProperties();
      DistributionConfig config = configMap.get(member);
      verifyGemFirePropertiesData(config, data);
    }
  }

  /**
   * Asserts that distribution config and gemfireProperty composite types hold the same values
   */
  private void verifyGemFirePropertiesData(final DistributionConfig config,
      final GemFireProperties data) {
    assertThat(data.getMemberName()).isEqualTo(config.getName());

    // **TODO **
    String memberGroups = null;

    assertThat(data.getMcastPort()).isEqualTo(config.getMcastPort());
    assertThat(data.getMcastAddress()).isEqualTo(config.getMcastAddress().getHostAddress());
    assertThat(data.getBindAddress()).isEqualTo(config.getBindAddress());
    assertThat(data.getTcpPort()).isEqualTo(config.getTcpPort());
    assertThat(removeVMDir(data.getCacheXMLFile()))
        .isEqualTo(removeVMDir(config.getCacheXmlFile().getAbsolutePath()));

    // **TODO **
    assertThat(data.getMcastTTL()).isEqualTo(config.getMcastTtl());
    assertThat(data.getServerBindAddress()).isEqualTo(config.getServerBindAddress());
    assertThat(data.getLocators()).isEqualTo(config.getLocators());

    // The start locator may contain a directory
    assertThat(removeVMDir(data.getStartLocator()))
        .isEqualTo(removeVMDir(config.getStartLocator()));
    assertThat(removeVMDir(data.getLogFile()))
        .isEqualTo(removeVMDir(config.getLogFile().getAbsolutePath()));
    assertThat(data.getLogLevel()).isEqualTo(config.getLogLevel());
    assertThat(data.isStatisticSamplingEnabled()).isEqualTo(config.getStatisticSamplingEnabled());
    assertThat(removeVMDir(data.getStatisticArchiveFile()))
        .isEqualTo(removeVMDir(config.getStatisticArchiveFile().getAbsolutePath()));

    // ** TODO **
    String includeFile = null;
    assertThat(data.getAckWaitThreshold()).isEqualTo(config.getAckWaitThreshold());
    assertThat(data.getAckSevereAlertThreshold()).isEqualTo(config.getAckSevereAlertThreshold());
    assertThat(data.getArchiveFileSizeLimit()).isEqualTo(config.getArchiveFileSizeLimit());
    assertThat(data.getArchiveDiskSpaceLimit()).isEqualTo(config.getArchiveDiskSpaceLimit());
    assertThat(data.getLogFileSizeLimit()).isEqualTo(config.getLogFileSizeLimit());
    assertThat(data.getLogDiskSpaceLimit()).isEqualTo(config.getLogDiskSpaceLimit());
    assertThat(data.isClusterSSLEnabled()).isEqualTo(config.getClusterSSLEnabled());

    assertThat(data.getClusterSSLCiphers()).isEqualTo(config.getClusterSSLCiphers());
    assertThat(data.getClusterSSLProtocols()).isEqualTo(config.getClusterSSLProtocols());
    assertThat(data.isClusterSSLRequireAuthentication())
        .isEqualTo(config.getClusterSSLRequireAuthentication());
    assertThat(data.getSocketLeaseTime()).isEqualTo(config.getSocketLeaseTime());
    assertThat(data.getSocketBufferSize()).isEqualTo(config.getSocketBufferSize());
    assertThat(data.getMcastSendBufferSize()).isEqualTo(config.getMcastSendBufferSize());
    assertThat(data.getMcastRecvBufferSize()).isEqualTo(config.getMcastRecvBufferSize());
    assertThat(data.getMcastByteAllowance())
        .isEqualTo(config.getMcastFlowControl().getByteAllowance());
    assertThat(data.getMcastRechargeThreshold())
        .isEqualTo(config.getMcastFlowControl().getRechargeThreshold());
    assertThat(data.getMcastRechargeBlockMs())
        .isEqualTo(config.getMcastFlowControl().getRechargeBlockMs());
    assertThat(data.getUdpFragmentSize()).isEqualTo(config.getUdpFragmentSize());
    assertThat(data.getUdpSendBufferSize()).isEqualTo(config.getUdpSendBufferSize());
    assertThat(data.getUdpRecvBufferSize()).isEqualTo(config.getUdpRecvBufferSize());
    assertThat(data.isDisableTcp()).isEqualTo(config.getDisableTcp());
    assertThat(data.isEnableTimeStatistics()).isEqualTo(config.getEnableTimeStatistics());
    assertThat(data.isEnableNetworkPartitionDetection())
        .isEqualTo(config.getEnableNetworkPartitionDetection());
    assertThat(data.getMemberTimeout()).isEqualTo(config.getMemberTimeout());

    assertThat(data.getMembershipPortRange()).containsExactly(config.getMembershipPortRange());

    assertThat(data.isConserveSockets()).isEqualTo(config.getConserveSockets());
    assertThat(data.getRoles()).isEqualTo(config.getRoles());
    assertThat(data.getMaxWaitTimeForReconnect()).isEqualTo(config.getMaxWaitTimeForReconnect());
    assertThat(data.getMaxNumReconnectTries()).isEqualTo(config.getMaxNumReconnectTries());
    assertThat(data.getAsyncDistributionTimeout()).isEqualTo(config.getAsyncDistributionTimeout());
    assertThat(data.getAsyncMaxQueueSize()).isEqualTo(config.getAsyncMaxQueueSize());
    assertThat(data.getClientConflation()).isEqualTo(config.getClientConflation());
    assertThat(data.getDurableClientId()).isEqualTo(config.getDurableClientId());
    assertThat(data.getDurableClientTimeout()).isEqualTo(config.getDurableClientTimeout());
    assertThat(data.getSecurityClientAuthInit()).isEqualTo(config.getSecurityClientAuthInit());
    assertThat(data.getSecurityClientAuthenticator())
        .isEqualTo(config.getSecurityClientAuthenticator());
    assertThat(data.getSecurityClientDHAlgo()).isEqualTo(config.getSecurityClientDHAlgo());
    assertThat(data.getSecurityPeerAuthInit()).isEqualTo(config.getSecurityPeerAuthInit());
    assertThat(data.getSecurityClientAuthenticator())
        .isEqualTo(config.getSecurityPeerAuthenticator());
    assertThat(data.getSecurityClientAccessor()).isEqualTo(config.getSecurityClientAccessor());
    assertThat(data.getSecurityClientAccessorPP()).isEqualTo(config.getSecurityClientAccessorPP());
    assertThat(data.getSecurityLogLevel()).isEqualTo(config.getSecurityLogLevel());
    assertThat(removeVMDir(data.getSecurityLogFile()))
        .isEqualTo(removeVMDir(config.getSecurityLogFile().getAbsolutePath()));
    assertThat(data.getSecurityPeerMembershipTimeout())
        .isEqualTo(config.getSecurityPeerMembershipTimeout());
    assertThat(data.isRemoveUnresponsiveClient()).isEqualTo(config.getRemoveUnresponsiveClient());
    assertThat(data.isDeltaPropagation()).isEqualTo(config.getDeltaPropagation());
    assertThat(data.getRedundancyZone()).isEqualTo(config.getRedundancyZone());
    assertThat(data.isEnforceUniqueHost()).isEqualTo(config.getEnforceUniqueHost());
    assertThat(data.getStatisticSampleRate()).isEqualTo(config.getStatisticSampleRate());
  }

  private void startManager() throws JMException {
    ManagementService service = this.managementTestRule.getManagementService();
    MemberMXBean memberMXBean = service.getMemberMXBean();
    if (memberMXBean.isManagerCreated()) {
      return;
    }

    // TODO: cleanup this mess
    // When the cache is created if jmx-managerVM is true then we create the managerVM.
    // So it may already exist when we get here.

    assertThat(memberMXBean.createManager()).isTrue();
    assertThat(memberMXBean.isManagerCreated()).isTrue();

    ManagerMXBean managerMXBean = service.getManagerMXBean();
    managerMXBean.start();

    assertThat(managerMXBean.isRunning()).isTrue();
    assertThat(memberMXBean.isManager()).isTrue();
    assertThat(service.isManager()).isTrue();
  }

  private String fetchLog(final int numberOfLines) {
    ManagementService service = this.managementTestRule.getManagementService();
    MemberMXBean memberMXBean = service.getMemberMXBean();
    return memberMXBean.showLog(numberOfLines);
  }

  private JVMMetrics fetchJVMMetrics() {
    ManagementService service = this.managementTestRule.getManagementService();
    MemberMXBean memberMXBean = service.getMemberMXBean();
    JVMMetrics metrics = memberMXBean.showJVMMetrics();
    return metrics;
  }

  private OSMetrics fetchOSMetrics() {
    ManagementService service = this.managementTestRule.getManagementService();
    MemberMXBean memberMXBean = service.getMemberMXBean();
    OSMetrics metrics = memberMXBean.showOSMetrics();
    return metrics;
  }

  private void shutDownMember() {
    ManagementService service = this.managementTestRule.getManagementService();
    MemberMXBean memberMXBean = service.getMemberMXBean();
    memberMXBean.shutDownMember();
  }

  private void verifyExpectedMembers(final int otherMembersCount) {
    String alias = "awaiting " + this.managementTestRule.getOtherNormalMembers() + " to have size "
        + otherMembersCount;
    GeodeAwaitility.await(alias)
        .untilAsserted(() -> assertThat(this.managementTestRule.getOtherNormalMembers())
            .hasSize(otherMembersCount));
  }

  private void invokeRemoteMemberMXBeanOps() {
    SystemManagementService service = this.managementTestRule.getSystemManagementService();
    Set<DistributedMember> otherMembers = this.managementTestRule.getOtherNormalMembers();

    for (DistributedMember member : otherMembers) {
      MemberMXBean memberMXBean = MXBeanAwaitility.awaitMemberMXBeanProxy(member, service);

      JVMMetrics metrics = memberMXBean.showJVMMetrics();

      String value = metrics.toString();
      boolean isManager = memberMXBean.isManager();

      // TODO: need assertions

      // ("<ExpectedString> JVMMetrics is " + metrics.toString() + "</ExpectedString> ");
      // ("<ExpectedString> OSMetrics is " + metrics.toString() + "</ExpectedString> ");
      // ("<ExpectedString> Boolean Data Check " + bean.isManager() + "</ExpectedString> ");
    }
  }

  private void attachListenerToDistributedSystemMXBean(final VM managerVM) {
    managerVM.invoke("attachListenerToDistributedSystemMXBean", () -> {
      ManagementService service = this.managementTestRule.getManagementService();
      assertThat(service.isManager()).isTrue();

      NotificationListener listener = (final Notification notification, final Object handback) -> {
        if (notification.getType().equals(JMXNotificationType.REGION_CREATED)) {
          notifications.add(notification);
        }
      };

      ManagementFactory.getPlatformMBeanServer().addNotificationListener(
          MBeanJMXAdapter.getDistributedSystemName(), listener, null, null);
    });
  }

  private void verifyNotificationsAndRegionSize(final VM memberVM1, final VM memberVM2,
      final VM memberVM3, final VM managerVM) {
    InternalDistributedMember member1 =
        (InternalDistributedMember) managementTestRule.getDistributedMember(memberVM1);
    InternalDistributedMember member2 =
        (InternalDistributedMember) managementTestRule.getDistributedMember(memberVM2);
    InternalDistributedMember member3 =
        (InternalDistributedMember) managementTestRule.getDistributedMember(memberVM3);

    String memberId1 = MBeanJMXAdapter.getUniqueIDForMember(member1);
    String memberId2 = MBeanJMXAdapter.getUniqueIDForMember(member2);
    String memberId3 = MBeanJMXAdapter.getUniqueIDForMember(member3);

    memberVM1.invoke("createNotificationRegion", () -> createNotificationRegion(memberId1));
    memberVM2.invoke("createNotificationRegion", () -> createNotificationRegion(memberId2));
    memberVM3.invoke("createNotificationRegion", () -> createNotificationRegion(memberId3));

    managerVM.invoke("verify notifications size", () -> {
      GeodeAwaitility.await().untilAsserted(() -> assertThat(notifications.size()).isEqualTo(45));

      Cache cache = this.managementTestRule.getCache();

      Region region1 = cache.getRegion(ManagementConstants.NOTIFICATION_REGION + "_" + memberId1);
      Region region2 = cache.getRegion(ManagementConstants.NOTIFICATION_REGION + "_" + memberId2);
      Region region3 = cache.getRegion(ManagementConstants.NOTIFICATION_REGION + "_" + memberId3);

      // Even though we got 15 notification only 10 should be there due to
      // eviction attributes set in notification region

      GeodeAwaitility.await().untilAsserted(() -> assertThat(region1).hasSize(10));
      GeodeAwaitility.await().untilAsserted(() -> assertThat(region2).hasSize(10));
      GeodeAwaitility.await().untilAsserted(() -> assertThat(region3).hasSize(10));
    });
  }

  private void createNotificationRegion(final String memberId) {
    SystemManagementService service = this.managementTestRule.getSystemManagementService();
    Map<ObjectName, NotificationHubListener> notificationHubListenerMap =
        service.getNotificationHub().getListenerObjectMap();

    GeodeAwaitility.await()
        .untilAsserted(() -> assertThat(notificationHubListenerMap.size()).isEqualTo(1));

    RegionFactory regionFactory =
        this.managementTestRule.getCache().createRegionFactory(RegionShortcut.REPLICATE);
    for (int i = 1; i <= 15; i++) {
      regionFactory.create(NOTIFICATION_REGION_NAME + i);
    }
    Region region = this.managementTestRule.getCache()
        .getRegion(ManagementConstants.NOTIFICATION_REGION + "_" + memberId);

    assertThat(region).isEmpty();
  }

  private static String removeVMDir(String string) {
    return string.replaceAll("vm.", "");
  }
}
