/*
 * 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.ignite.spi.discovery.tcp.ipfinder.zk;

import java.util.Collection;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.retry.RetryNTimes;
import org.apache.curator.test.InstanceSpec;
import org.apache.curator.test.TestingCluster;
import org.apache.curator.utils.CloseableUtils;
import org.apache.ignite.Ignite;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.events.Event;
import org.apache.ignite.events.EventType;
import org.apache.ignite.lang.IgniteBiPredicate;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.junits.WithSystemProperty;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

/**
 * Test for {@link TcpDiscoveryZookeeperIpFinder}.
 *
 * @author Raul Kripalani
 */
@WithSystemProperty(key = "zookeeper.jmx.log4j.disable", value = "true") // disable JMX for tests
public class ZookeeperIpFinderTest extends GridCommonAbstractTest {
    /** Per test timeout */
    @Rule
    public Timeout globalTimeout = new Timeout((int)GridTestUtils.DFLT_TEST_TIMEOUT);

    /** ZK Cluster size. */
    private static final int ZK_CLUSTER_SIZE = 3;

    /** ZK Path size. */
    private static final String SERVICES_IGNITE_ZK_PATH = "/services/ignite";

    /** The ZK cluster instance, from curator-test. */
    private TestingCluster zkCluster;

    /** A Curator client to perform assertions on the embedded ZK instances. */
    private CuratorFramework zkCurator;

    /** Whether to allow duplicate registrations for the current test method or not. */
    private boolean allowDuplicateRegistrations = false;

    /** Constructor that does not start any grids. */
    public ZookeeperIpFinderTest() {
        super(false);
    }

    /**
     * Before test.
     *
     * @throws Exception
     */
    @Override public void beforeTest() throws Exception {
        super.beforeTest();

        // remove stale system properties
        System.getProperties().remove(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING);

        // start the ZK cluster
        zkCluster = new TestingCluster(ZK_CLUSTER_SIZE);

        zkCluster.start();

        // start the Curator client so we can perform assertions on the ZK state later
        zkCurator = CuratorFrameworkFactory.newClient(zkCluster.getConnectString(), new RetryNTimes(10, 1000));
        zkCurator.start();
    }

    /**
     * After test.
     *
     * @throws Exception
     */
    @Override public void afterTest() throws Exception {
        super.afterTest();

        if (zkCurator != null)
            CloseableUtils.closeQuietly(zkCurator);

        if (zkCluster != null)
            CloseableUtils.closeQuietly(zkCluster);

        stopAllGrids();
    }

    /**
     * Enhances the default configuration with the {#TcpDiscoveryZookeeperIpFinder}.
     *
     * @param igniteInstanceName Ignite instance name.
     * @return Ignite configuration.
     * @throws Exception If failed.
     */
    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
        IgniteConfiguration configuration = super.getConfiguration(igniteInstanceName);

        TcpDiscoverySpi tcpDisco = (TcpDiscoverySpi)configuration.getDiscoverySpi();
        TcpDiscoveryZookeeperIpFinder zkIpFinder = new TcpDiscoveryZookeeperIpFinder();
        zkIpFinder.setAllowDuplicateRegistrations(allowDuplicateRegistrations);

        // first node => configure with zkUrl; second node => configure with CuratorFramework; third and subsequent
        // shall be configured through system property
        if (igniteInstanceName.equals(getTestIgniteInstanceName(0)))
            zkIpFinder.setZkConnectionString(zkCluster.getConnectString());

        else if (igniteInstanceName.equals(getTestIgniteInstanceName(1))) {
            zkIpFinder.setCurator(CuratorFrameworkFactory.newClient(zkCluster.getConnectString(),
                new ExponentialBackoffRetry(100, 5)));
        }

        tcpDisco.setIpFinder(zkIpFinder);

        return configuration;
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testOneIgniteNodeIsAlone() throws Exception {
        startGrid(0);

        assertEquals(1, grid(0).cluster().metrics().getTotalNodes());

        stopAllGrids();
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testTwoIgniteNodesFindEachOther() throws Exception {
        // start one node
        startGrid(0);

        // set up an event listener to expect one NODE_JOINED event
        CountDownLatch latch = expectJoinEvents(grid(0), 1);

        // start the other node
        startGrid(1);

        // assert the nodes see each other
        assertEquals(2, grid(0).cluster().metrics().getTotalNodes());
        assertEquals(2, grid(1).cluster().metrics().getTotalNodes());

        // assert the event listener got as many events as expected
        latch.await(1, TimeUnit.SECONDS);

        stopAllGrids();
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testThreeNodesWithThreeDifferentConfigMethods() throws Exception {
        // start one node
        startGrid(0);

        // set up an event listener to expect one NODE_JOINED event
        CountDownLatch latch = expectJoinEvents(grid(0), 2);

        // start the 2nd node
        startGrid(1);

        // start the 3rd node, first setting the system property
        System.setProperty(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING, zkCluster.getConnectString());
        startGrid(2);

        // wait until all grids are started
        waitForRemoteNodes(grid(0), 2);

        // assert the nodes see each other
        assertEquals(3, grid(0).cluster().metrics().getTotalNodes());
        assertEquals(3, grid(1).cluster().metrics().getTotalNodes());
        assertEquals(3, grid(2).cluster().metrics().getTotalNodes());

        // assert the event listener got as many events as expected
        latch.await(1, TimeUnit.SECONDS);

        stopAllGrids();
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testFourNodesStartingAndStopping() throws Exception {
        // start one node
        startGrid(0);

        // set up an event listener to expect one NODE_JOINED event
        CountDownLatch latch = expectJoinEvents(grid(0), 3);

        // start the 2nd node
        startGrid(1);

        // start the 3rd & 4th nodes, first setting the system property
        System.setProperty(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING, zkCluster.getConnectString());
        startGrid(2);
        startGrid(3);

        // wait until all grids are started
        waitForRemoteNodes(grid(0), 3);

        // assert the nodes see each other
        assertEquals(4, grid(0).cluster().metrics().getTotalNodes());
        assertEquals(4, grid(1).cluster().metrics().getTotalNodes());
        assertEquals(4, grid(2).cluster().metrics().getTotalNodes());
        assertEquals(4, grid(3).cluster().metrics().getTotalNodes());

        // assert the event listener got as many events as expected
        latch.await(1, TimeUnit.SECONDS);

        // stop the first grid
        stopGrid(0);

        // make sure that nodes were synchronized; they should only see 3 now
        assertEquals(3, grid(1).cluster().metrics().getTotalNodes());
        assertEquals(3, grid(2).cluster().metrics().getTotalNodes());
        assertEquals(3, grid(3).cluster().metrics().getTotalNodes());

        // stop all remaining grids
        stopGrid(1);
        stopGrid(2);
        stopGrid(3);

        // check that the nodes are gone in ZK
        assertEquals(0, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testFourNodesWithDuplicateRegistrations() throws Exception {
        allowDuplicateRegistrations = true;

        // start 4 nodes
        System.setProperty(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING, zkCluster.getConnectString());
        startGrids(4);

        // wait until all grids are started
        waitForRemoteNodes(grid(0), 3);

        // each node will register itself + the node that it connected to to join the cluster
        assertEquals(7, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());

        // stop all grids
        stopAllGrids();

        // check that all nodes are gone in ZK
        assertEquals(0, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testFourNodesWithNoDuplicateRegistrations() throws Exception {
        allowDuplicateRegistrations = false;

        // start 4 nodes
        System.setProperty(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING, zkCluster.getConnectString());
        startGrids(4);

        // wait until all grids are started
        waitForRemoteNodes(grid(0), 3);

        // each node will only register itself
        assertEquals(4, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());

        // stop all grids
        stopAllGrids();

        // check that all nodes are gone in ZK
        assertEquals(0, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testFourNodesRestartLastSeveralTimes() throws Exception {
        allowDuplicateRegistrations = false;

        // start 4 nodes
        System.setProperty(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING, zkCluster.getConnectString());
        startGrids(4);

        // wait until all grids are started
        waitForRemoteNodes(grid(0), 3);

        // each node will only register itself
        assertEquals(4, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());

        // repeat 5 times
        for (int i = 0; i < 5; i++) {
            // stop last grid
            stopGrid(2);

            // check that the node has unregistered itself and its party
            assertEquals(3, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());

            // start the node again
            startGrid(2);

            // check that the node back in ZK
            assertEquals(4, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());
        }

        stopAllGrids();

        assertEquals(0, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());
    }

    /**
     * @throws Exception If failed.
     */
    @Test
    public void testFourNodesKillRestartZookeeper() throws Exception {
        allowDuplicateRegistrations = false;

        // start 4 nodes
        System.setProperty(TcpDiscoveryZookeeperIpFinder.PROP_ZK_CONNECTION_STRING, zkCluster.getConnectString());
        startGrids(4);

        // wait until all grids are started
        waitForRemoteNodes(grid(0), 3);

        // each node will only register itself
        assertEquals(4, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());

        // remember ZK server configuration and stop the cluster
        Collection<InstanceSpec> instances = zkCluster.getInstances();
        zkCluster.stop();
        Thread.sleep(1000);

        // start the cluster with the previous configuration
        zkCluster = new TestingCluster(instances);
        zkCluster.start();

        // block the client until connected
        zkCurator.blockUntilConnected();

        // Check that the nodes have registered again with the previous configuration.
        assertEquals(4, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());

        // Block the clients until connected.
        for (int i = 0; i < 4; i++) {
            TcpDiscoverySpi spi = (TcpDiscoverySpi)grid(i).configuration().getDiscoverySpi();

            TcpDiscoveryZookeeperIpFinder zkIpFinder = (TcpDiscoveryZookeeperIpFinder)spi.getIpFinder();

            CuratorFramework curator = GridTestUtils.getFieldValue(zkIpFinder, "curator");

            curator.blockUntilConnected();
        }

        // stop all grids
        stopAllGrids();

        assertEquals(0, zkCurator.getChildren().forPath(SERVICES_IGNITE_ZK_PATH).size());
    }

    /**
     * @param ignite Node.
     * @param joinEvtCnt Expected events number.
     * @return Events latch.
     */
    private CountDownLatch expectJoinEvents(Ignite ignite, int joinEvtCnt) {
        final CountDownLatch latch = new CountDownLatch(joinEvtCnt);

        ignite.events().remoteListen(new IgniteBiPredicate<UUID, Event>() {
            @Override public boolean apply(UUID uuid, Event evt) {
                latch.countDown();
                return true;
            }
        }, null, EventType.EVT_NODE_JOINED);

        return latch;
    }
}
