/*
 * 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.internal.cache.tier.sockets;

import static org.apache.geode.cache.Region.SEPARATOR;
import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
import static org.apache.geode.internal.AvailablePortHelper.getRandomAvailableTCPPort;
import static org.apache.geode.test.dunit.Assert.assertEquals;
import static org.apache.geode.test.dunit.Assert.assertFalse;
import static org.apache.geode.test.dunit.Assert.assertNotNull;
import static org.apache.geode.test.dunit.Assert.assertTrue;
import static org.apache.geode.test.dunit.Assert.fail;

import java.util.Iterator;
import java.util.Properties;

import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.client.internal.PoolImpl;
import org.apache.geode.cache.query.CqAttributes;
import org.apache.geode.cache.query.CqAttributesFactory;
import org.apache.geode.cache.query.CqQuery;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.cache.CacheServerImpl;
import org.apache.geode.test.awaitility.GeodeAwaitility;
import org.apache.geode.test.dunit.Host;
import org.apache.geode.test.dunit.NetworkUtils;
import org.apache.geode.test.dunit.VM;
import org.apache.geode.test.dunit.Wait;
import org.apache.geode.test.dunit.WaitCriterion;
import org.apache.geode.test.dunit.internal.JUnit4DistributedTestCase;
import org.apache.geode.test.junit.categories.ClientSubscriptionTest;
import org.apache.geode.test.junit.categories.SerializationTest;

/**
 * This tests the flag setting for region ( DataPolicy as Empty ) for Delta propogation for a client
 * while registering CQ
 */
@Category({ClientSubscriptionTest.class, SerializationTest.class})
public class DeltaToRegionRelationCQRegistrationDUnitTest extends JUnit4DistributedTestCase {

  private static Cache cache = null;

  private VM server = null;
  private VM client = null;
  private VM server2 = null;
  private VM client2 = null;

  private int PORT1;
  private int PORT2;

  private static PoolImpl p = null;

  /*
   * name of the region with data policy empty
   */
  private static final String REGION_NAME1 = "DeltaToRegionRelationCQRegistration_region1";

  /*
   * name of the region whose data policy is not empty
   */
  private static final String REGION_NAME2 = "DeltaToRegionRelationCQRegistration_region2";

  /*
   * to detect primary server
   */
  private static Integer primary = null;

  /*
   * cq 1
   */
  private static final String CQ1 = "SELECT * FROM " + SEPARATOR + REGION_NAME1;

  /*
   * cq 2
   */
  private static final String CQ2 = "SELECT * FROM " + SEPARATOR + REGION_NAME2;

  /*
   * cq 3
   */
  private static final String CQ3 = "SELECT ALL * FROM " + SEPARATOR + REGION_NAME1;

  /*
   * cq 4
   */
  private static final String CQ4 = "SELECT ALL * FROM " + SEPARATOR + REGION_NAME2;

  private static final String cqName1 = "cqNameFirst";
  private static final String cqName2 = "cqNameSecond";
  private static final String cqName3 = "cqNamethird";
  private static final String cqName4 = "cqNameFourth";

  @Override
  public final void postSetUp() throws Exception {
    disconnectAllFromDS();
    Wait.pause(5000);
    final Host host = Host.getHost(0);
    server = host.getVM(0);
    client = host.getVM(1);
    server2 = host.getVM(2);
    client2 = host.getVM(3);
  }

  /**
   * This test does the following for single cq registration(<b>with out initial resultset</b>):<br>
   * 1)Verifies create entry for region with data policy as Empty; in map stored in CacheCleintProxy
   * <br>
   * 2)Verifies no create happens for region with data policy other then Empty; in map <br>
   * 3)Verifies multiple and different interest registration (key/list) should not create multiple
   * entries in map <br>
   */
  @Test
  public void testDeltaToRegionForRegisterCQ() {

    intialSetUp();

    // Register CQ on region with data policy as EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName1, CQ1,
        Boolean.FALSE));

    // Register CQ on region with data policy other then EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName2, CQ2,
        Boolean.FALSE));

    // validation on server side
    server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);

    // check for multiple time cq registration
    // Register CQ on region with data policy as EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName3, CQ3,
        Boolean.FALSE));

    // Register CQ on region with data policy as EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName4, CQ4,
        Boolean.TRUE));

    // validation on server side
    server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);

    tearDownforSimpleCase();
  }

  /**
   * This test does the following for single cq registration(<b>with initial resultset</b>):<br>
   * 1)Verifies create entry for region with data policy as Empty; in map stored in CacheCleintProxy
   * <br>
   * 2)Verifies no create happens for region with data policy other then Empty; in map <br>
   * 3)Verifies multiple and different interest registration (key/list) should not create multiple
   * entries in map <br>
   */
  @Test
  public void testDeltaToRegionForRegisterCQIR() {

    intialSetUp();

    // Register CQ on region with data policy as EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName1, CQ1,
        Boolean.TRUE));

    // Register CQ on region with data policy other then EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName2, CQ2,
        Boolean.TRUE));

    // validation on server side
    server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);

    // check for multiple time registration Interest

    // Register CQ on region with data policy as EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName3, CQ3,
        Boolean.TRUE));

    // Register CQ on region with data policy as EMPTY
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName4, CQ4,
        Boolean.FALSE));

    // validation on server side
    server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);

    tearDownforSimpleCase();
  }

  /**
   * This test does the following for single cq registration from pool (<b>with initial
   * resultset</b>):<br>
   * 1)Verifies create entry for region in map stored in CacheCleintProxy <br>
   * 2)Verifies multiple and different interest registration (key/list) should not create multiple
   * entries in map <br>
   */
  @Test
  public void testDeltaToRegionForRegisterCQIRThroughPool() {

    intialSetUpClientWithNoRegion();

    // Register CQ on region
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCqThroughPool(cqName1,
        CQ1, Boolean.TRUE));

    // Register CQ on region
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCqThroughPool(cqName2,
        CQ2, Boolean.TRUE));

    // validation on server side
    server.invoke(
        DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServerForCqRegistrationFromPool);

    // check for multiple time registration cq

    // Register CQ on region
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCqThroughPool(cqName3,
        CQ3, Boolean.TRUE));

    // Register CQ on region
    // CQ registration
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCqThroughPool(cqName4,
        CQ4, Boolean.FALSE));

    // validation on server side
    server.invoke(
        DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServerForCqRegistrationFromPool);

    tearDownforSimpleCase();
  }


  /**
   * This test does the following for cq registration when <b>failover</b>(<b>cq
   * registration</b>):<br>
   * 1)Verifies when primary goes down, cq registration happen <br>
   * 2)Verifies create entry for region with data policy as Empty; in map stored in CacheCleintProxy
   * <br>
   * 3)Verifies no create happens for region with data policy other then Empty; in map <br>
   */
  @Test
  public void testDeltaToRegionForRegisterCQFailover() {

    intialSetUpForFailOver();
    // Register CQ on region with data policy as EMPTY
    client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName1, CQ1,
        Boolean.FALSE));
    // Register CQ on region with data policy other then EMPTY
    client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName2, CQ2,
        Boolean.FALSE));

    validationForFailOver();
    tearDownForFailOver();
  }

  /**
   * This test does the following for cq registration with initial result set when
   * <b>failover</b>(<b>cq registration</b>):<br>
   * 1)Verifies when primary goes down, cq registration happen <br>
   * 2)Verifies create entry for region with data policy as Empty; in map stored in CacheCleintProxy
   * <br>
   * 3)Verifies no create happens for region with data policy other then Empty; in map <br>
   */
  @Test
  public void testDeltaToRegionForRegisterCQIRFaliover() {
    intialSetUpForFailOver();
    // Register CQ on region with data policy as EMPTY
    client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName1, CQ1,
        Boolean.TRUE));

    // Register CQ on region with data policy other then EMPTY
    client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCq(cqName2, CQ2,
        Boolean.TRUE));

    validationForFailOver();
    tearDownForFailOver();
  }

  /**
   * This test does the following for cq registration with initial result set through pool when
   * <b>failover</b>(<b>cq registration</b>):<br>
   * 1)Verifies when primary goes down, cq registration happen <br>
   * 2)Verifies create entry for region in map stored in CacheCleintProxy <br>
   */
  @Test
  public void testDeltaToRegionForRegisterCQIRFromPoolFaliover() {
    intialSetUpNoRegiononClientForFailOver();
    // Register CQ on region
    client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCqThroughPool(cqName1,
        CQ1, Boolean.TRUE));

    // Register CQ on region
    client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.registerCqThroughPool(cqName2,
        CQ2, Boolean.TRUE));

    validationForCQFiredFromPoolFailOver();
    tearDownForFailOver();
  }

  /*
   * register cq
   */
  public static void registerCq(String name, String Cquery, Boolean cqWithIR) {
    QueryService cqService = null;
    // get cq service
    try {
      cqService = cache.getQueryService();
    } catch (Exception cqe) {
      cqe.printStackTrace();
      fail("Failed to getCqService.");
    }

    // Create CQ Attributes.
    // do not attach any listiner lets see its response
    CqAttributesFactory cqf = new CqAttributesFactory();
    CqAttributes cqa = cqf.create();

    // Create and Execute CQ.
    try {
      CqQuery cq1 = cqService.newCq(name, Cquery, cqa);
      assertTrue("newCq() state mismatch", cq1.getState().isStopped());
      if (cqWithIR) {
        cq1.executeWithInitialResults();
      } else {
        cq1.execute();
      }
    } catch (Exception ex) {
      fail("Failed to create CQ " + cqName1, ex);
    }

    CqQuery cQuery = cqService.getCq(name);
    if (cQuery == null) {
      fail("Failed to get CqQuery for CQ : " + cqName1);
    }
  }

  /*
   * register cq from pool
   */
  public static void registerCqThroughPool(String name, String Cquery, Boolean cqWithIR) {
    QueryService cqService = null;
    // get cq service
    try {
      cqService = p.getQueryService();
    } catch (Exception cqe) {
      cqe.printStackTrace();
      fail("Failed to getCqService.");
    }

    // Create CQ Attributes.
    // do not attach any listiner lets see its response
    CqAttributesFactory cqf = new CqAttributesFactory();
    CqAttributes cqa = cqf.create();

    // Create and Execute CQ.
    try {
      CqQuery cq1 = cqService.newCq(name, Cquery, cqa);
      assertTrue("newCq() state mismatch", cq1.getState().isStopped());
      if (cqWithIR) {
        cq1.executeWithInitialResults();
      } else {
        cq1.execute();
      }
    } catch (Exception ex) {
      fail("Failed to create CQ " + cqName1, ex);
    }

    CqQuery cQuery = cqService.getCq(name);
    if (cQuery == null) {
      fail("Failed to get CqQuery for CQ : " + cqName1);
    }
  }

  public static void validationOnServer() throws Exception {
    checkNumberOfClientProxies(1);
    CacheClientProxy proxy = getClientProxy();
    assertNotNull(proxy);
    WaitCriterion wc = new WaitCriterion() {
      @Override
      public boolean done() {
        return getClientProxy()
            .getRegionsWithEmptyDataPolicy().containsKey(SEPARATOR + REGION_NAME1);
      }

      @Override
      public String description() {
        return "Wait Expired";
      }
    };
    GeodeAwaitility.await().untilAsserted(wc);

    assertTrue(REGION_NAME1 + " not present in cache client proxy : Delta is enable",
        proxy.getRegionsWithEmptyDataPolicy()
            .containsKey(SEPARATOR + REGION_NAME1)); /*
                                                      * Empty data policy
                                                      */
    assertFalse(REGION_NAME2 + " present in cache client proxy : Delta is disable",
        proxy.getRegionsWithEmptyDataPolicy()
            .containsKey(SEPARATOR + REGION_NAME2)); /*
                                                      * other then Empty data policy
                                                      */
    assertTrue("Multiple entries for a region", proxy.getRegionsWithEmptyDataPolicy().size() == 1);
    assertTrue("Wrong ordinal stored for empty data policy",
        proxy.getRegionsWithEmptyDataPolicy().get(SEPARATOR + REGION_NAME1) == 0);

  }

  public static void validationOnServerForCqRegistrationFromPool() throws Exception {
    checkNumberOfClientProxies(1);
    CacheClientProxy proxy = getClientProxy();
    assertNotNull(proxy);

    WaitCriterion wc = new WaitCriterion() {
      @Override
      public boolean done() {
        return getClientProxy()
            .getRegionsWithEmptyDataPolicy().containsKey(SEPARATOR + REGION_NAME1)
            && getClientProxy()
                .getRegionsWithEmptyDataPolicy().containsKey(SEPARATOR + REGION_NAME2);
      }

      @Override
      public String description() {
        return "Wait Expired";
      }
    };
    GeodeAwaitility.await().untilAsserted(wc);

    assertTrue("Multiple entries for a region", proxy.getRegionsWithEmptyDataPolicy().size() == 2);

    assertTrue("Wrong ordinal stored for empty data policy",
        proxy.getRegionsWithEmptyDataPolicy().get(SEPARATOR + REGION_NAME1) == 0);

    assertTrue("Wrong ordinal stored for empty data policy",
        proxy.getRegionsWithEmptyDataPolicy().get(SEPARATOR + REGION_NAME2) == 0);

  }

  /*
   * create server cache
   */
  public static Integer createServerCache() throws Exception {
    new DeltaToRegionRelationCQRegistrationDUnitTest().createCache(new Properties());
    AttributesFactory factory = new AttributesFactory();
    factory.setScope(Scope.DISTRIBUTED_ACK);
    factory.setDataPolicy(DataPolicy.REPLICATE);
    RegionAttributes attrs = factory.create();
    cache.createRegion(REGION_NAME1, attrs);
    cache.createRegion(REGION_NAME2, attrs);

    CacheServer server = cache.addCacheServer();
    int port = getRandomAvailableTCPPort();
    server.setPort(port);
    // ensures updates to be sent instead of invalidations
    server.setNotifyBySubscription(true);
    server.start();
    return server.getPort();

  }

  /*
   * create client cache
   */
  public static void createClientCache(String host, Integer port) throws Exception {
    Properties props = new Properties();
    props.setProperty(MCAST_PORT, "0");
    props.setProperty(LOCATORS, "");
    new DeltaToRegionRelationCQRegistrationDUnitTest().createCache(props);
    Pool p = PoolManager.createFactory().addServer(host, port)
        .setMinConnections(3).setSubscriptionEnabled(true)
        .setSubscriptionRedundancy(0).setReadTimeout(10000).setSocketBufferSize(32768)
        // .setRetryInterval(10000)
        // .setRetryAttempts(5)
        .create("DeltaToRegionRelationCQRegistrationTestPool");
    AttributesFactory factory = new AttributesFactory();
    factory.setScope(Scope.DISTRIBUTED_ACK);
    factory.setDataPolicy(DataPolicy.EMPTY);
    factory.setPoolName(p.getName());
    factory.setCloningEnabled(false);

    // region with empty data policy
    RegionAttributes attrs = factory.create();
    cache.createRegion(REGION_NAME1, attrs);

    assertFalse(cache.getRegion(REGION_NAME1).getAttributes().getCloningEnabled());
    factory.setDataPolicy(DataPolicy.NORMAL);
    attrs = factory.create();
    // region with non empty data policy
    cache.createRegion(REGION_NAME2, attrs);
    assertFalse(cache.getRegion(REGION_NAME2).getAttributes().getCloningEnabled());
    cache.getRegion(REGION_NAME2).getAttributesMutator().setCloningEnabled(true);
    assertTrue(cache.getRegion(REGION_NAME2).getAttributes().getCloningEnabled());
  }

  /*
   * create client cache
   */
  public static void createClientCacheWithNoRegion(String host, Integer port) throws Exception {
    Properties props = new Properties();
    props.setProperty(MCAST_PORT, "0");
    props.setProperty(LOCATORS, "");
    new DeltaToRegionRelationCQRegistrationDUnitTest().createCache(props);
    p = (PoolImpl) PoolManager.createFactory().addServer(host, port)
        .setMinConnections(3).setSubscriptionEnabled(true)
        .setSubscriptionRedundancy(0).setReadTimeout(10000).setSocketBufferSize(32768)
        // .setRetryInterval(10000)
        // .setRetryAttempts(5)
        .create("DeltaToRegionRelationCQRegistrationTestPool");
  }

  /*
   * create client cache and return's primary server location object (primary)
   */
  public static Integer createClientCache2(String host1, String host2, Integer port1, Integer port2)
      throws Exception {
    Properties props = new Properties();
    props.setProperty(MCAST_PORT, "0");
    props.setProperty(LOCATORS, "");
    new DeltaToRegionRelationCQRegistrationDUnitTest().createCache(props);
    PoolImpl p = (PoolImpl) PoolManager.createFactory().addServer(host1, port1)
        .addServer(host2, port2).setMinConnections(3)
        .setSubscriptionEnabled(true).setSubscriptionRedundancy(0).setReadTimeout(10000)
        .setSocketBufferSize(32768)
        // .setRetryInterval(10000)
        // .setRetryAttempts(5)
        .create("DeltaToRegionRelationCQRegistrationTestPool");
    AttributesFactory factory = new AttributesFactory();
    factory.setScope(Scope.DISTRIBUTED_ACK);
    factory.setDataPolicy(DataPolicy.EMPTY);
    factory.setPoolName(p.getName());

    // region with empty data policy
    RegionAttributes attrs = factory.create();
    cache.createRegion(REGION_NAME1, attrs);

    factory.setDataPolicy(DataPolicy.NORMAL);
    attrs = factory.create();
    // region with non empty data policy
    cache.createRegion(REGION_NAME2, attrs);

    return p.getPrimaryPort();
  }

  /*
   * create client cache and return's primary server location object (primary) no region created on
   * client
   */
  public static Integer createClientCache3(String host1, String host2, Integer port1, Integer port2)
      throws Exception {
    Properties props = new Properties();
    props.setProperty(MCAST_PORT, "0");
    props.setProperty(LOCATORS, "");
    new DeltaToRegionRelationCQRegistrationDUnitTest().createCache(props);
    p = (PoolImpl) PoolManager.createFactory().addServer(host1, port1)
        .addServer(host2, port2).setMinConnections(3)
        .setSubscriptionEnabled(true).setSubscriptionRedundancy(0).setReadTimeout(10000)
        .setSocketBufferSize(32768)
        // .setRetryInterval(10000)
        // .setRetryAttempts(5)
        .create("DeltaToRegionRelationCQRegistrationTestPool");
    return p.getPrimaryPort();
  }

  /*
   * close cache
   */
  public static void closeCache() {
    if (cache != null && !cache.isClosed()) {
      cache.close();
      cache.getDistributedSystem().disconnect();
    }
  }

  /*
   * get cache client proxy object
   */
  public static CacheClientProxy getClientProxy() {
    // Get the CacheClientNotifier
    CacheClientNotifier notifier = getBridgeServer().getAcceptor().getCacheClientNotifier();

    // Get the CacheClientProxy or not (if proxy set is empty)
    CacheClientProxy proxy = null;
    Iterator i = notifier.getClientProxies().iterator();
    if (i.hasNext()) {
      proxy = (CacheClientProxy) i.next();
    }
    return proxy;
  }

  /*
   * get cache server / cache server attacted to cache
   */
  private static CacheServerImpl getBridgeServer() {
    CacheServerImpl bridgeServer = (CacheServerImpl) cache.getCacheServers().iterator().next();
    assertNotNull(bridgeServer);
    return bridgeServer;
  }

  /*
   * number of client proxies are presert
   */
  private static int getNumberOfClientProxies() {
    return getBridgeServer().getAcceptor().getCacheClientNotifier().getClientProxies().size();
  }

  /*
   * if expected number of proxies are not present and wait
   */
  private static void checkNumberOfClientProxies(int expected) {
    int current = getNumberOfClientProxies();
    int tries = 1;
    while (expected != current && tries++ < 60) {
      try {
        Thread.sleep(250);
      } catch (InterruptedException ignore) {
        Thread.currentThread().interrupt(); // reset bit
      }
      current = getNumberOfClientProxies();
    }
    assertEquals(expected, current);
  }

  /*
   * stop cache server
   */
  public static void stopCacheServer() {
    getBridgeServer().stop();
  }

  /*
   * initial setup required for testcase with out failover
   */
  public void intialSetUp() {
    PORT1 = server
        .invoke(DeltaToRegionRelationCQRegistrationDUnitTest::createServerCache);
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest
        .createClientCache(NetworkUtils.getServerHostName(server.getHost()), PORT1));
  }

  /*
   * initial setup required for testcase with out failover
   */
  public void intialSetUpClientWithNoRegion() {
    PORT1 = server
        .invoke(DeltaToRegionRelationCQRegistrationDUnitTest::createServerCache);
    client.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest.createClientCacheWithNoRegion(
        NetworkUtils.getServerHostName(server.getHost()), PORT1));
  }

  /*
   * kind of teardown for testcase without failover
   */
  public void tearDownforSimpleCase() {
    // close the clients first
    client.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::closeCache);
    // then close the servers
    server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::closeCache);
  }

  /*
   * initial setup required for testcase with failover
   */
  public void intialSetUpForFailOver() {
    PORT1 = server
        .invoke(DeltaToRegionRelationCQRegistrationDUnitTest::createServerCache);
    // used only in failover tests
    PORT2 = server2
        .invoke(DeltaToRegionRelationCQRegistrationDUnitTest::createServerCache);
    primary = client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest
        .createClientCache2(NetworkUtils.getServerHostName(server.getHost()),
            NetworkUtils.getServerHostName(server2.getHost()), PORT1,
            PORT2));
  }

  /*
   * initial setup required for testcase with failover where we don't need region on client
   */
  public void intialSetUpNoRegiononClientForFailOver() {
    PORT1 = server
        .invoke(DeltaToRegionRelationCQRegistrationDUnitTest::createServerCache);
    // used only in failover tests
    PORT2 = server2
        .invoke(DeltaToRegionRelationCQRegistrationDUnitTest::createServerCache);
    primary = client2.invoke(() -> DeltaToRegionRelationCQRegistrationDUnitTest
        .createClientCache3(NetworkUtils.getServerHostName(server.getHost()),
            NetworkUtils.getServerHostName(server2.getHost()), PORT1,
            PORT2));
  }

  /*
   * find out primary and stop it register CQ whould happened on other server
   */
  public void validationForFailOver() {
    assertTrue(" primary server is not detected ", primary != -1);
    if (primary == PORT1) {
      server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);
      server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::stopCacheServer);
      server2.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);
    } else {
      server2.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);
      server2.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::stopCacheServer);
      server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServer);
    }
  }

  /*
   * find out primary and stop it register CQ whould happened on other server
   */
  public void validationForCQFiredFromPoolFailOver() {
    assertTrue(" primary server is not detected ", primary != -1);
    if (primary == PORT1) {
      server.invoke(
          DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServerForCqRegistrationFromPool);
      server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::stopCacheServer);
      server2.invoke(
          DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServerForCqRegistrationFromPool);
    } else {
      server2.invoke(
          DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServerForCqRegistrationFromPool);
      server2.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::stopCacheServer);
      server.invoke(
          DeltaToRegionRelationCQRegistrationDUnitTest::validationOnServerForCqRegistrationFromPool);
    }
  }

  /*
   * kind of teardown for testcase with failover
   */
  public void tearDownForFailOver() {
    // close the clients first
    client2.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::closeCache);
    // then close the servers
    server.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::closeCache);
    server2.invoke(DeltaToRegionRelationCQRegistrationDUnitTest::closeCache);
  }

  /*
   * create cache with properties
   */
  private void createCache(Properties props) throws Exception {
    DistributedSystem ds = getSystem(props);
    cache = CacheFactory.create(ds);
    assertNotNull(cache);
  }
}
