/*
 * 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;
    }
}
