package com.atlassian.stash.internal.cluster;

import com.atlassian.bitbucket.cluster.ClusterInformation;
import com.atlassian.bitbucket.cluster.ClusterNode;
import com.atlassian.bitbucket.license.LicenseService;
import com.atlassian.extras.api.bitbucket.BitbucketServerLicense;
import com.atlassian.hazelcast.test.HazelcastCluster;
import com.google.common.collect.Iterables;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

import java.util.HashSet;
import java.util.Set;

import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

//This is a unified integration test for the entire HazelcastCluster* set of classes. It does _not_ cover every
//code path in the various classes, which is why the mock tests also exist.
@RunWith(MockitoJUnitRunner.class)
public class HazelcastClusterServiceTest {

    @ClassRule
    public static final HazelcastCluster cluster = new HazelcastCluster.Builder().size(2).build();

    @Mock
    private LicenseService licenseService;

    private HazelcastClusterService service;

    @Before
    public void setup() {
        service = new HazelcastClusterService(cluster.getNode(0), licenseService);

        BitbucketServerLicense mockLicense = mock(BitbucketServerLicense.class);
        when(mockLicense.isClusteringEnabled()).thenReturn(true);
        when(licenseService.get()).thenReturn(mockLicense);
    }

    @Test
    public void testGetInformation() {
        ClusterInformation information = service.getInformation();
        assertNotNull(information);
        assertTrue(information.isRunning());

        ClusterNode localNode = information.getLocalNode();
        assertNotNull(localNode.getAddress());
        assertNotNull(localNode.getId());
        assertTrue(localNode.isLocal());

        Set<ClusterNode> nodes = information.getNodes();
        assertNotNull(nodes);
        assertEquals(2, nodes.size());

        //This verifies equality relationships work for HazelcastClusterNode. Since ClusterInformation offers both
        //getLocalNode() and getNodes(), it's important to have the ability to locate that node in the set
        nodes = new HashSet<>(nodes);
        assertTrue(nodes.remove(localNode));

        ClusterNode remoteNode = Iterables.getOnlyElement(nodes);
        assertNotNull(remoteNode.getAddress());
        assertNotNull(remoteNode.getId());
        assertNotEquals(localNode.getAddress(), remoteNode.getAddress());
        assertNotEquals(localNode.getId(), remoteNode.getId());
        assertFalse(remoteNode.isLocal());
    }

    @Test
    public void testIsAvailable() {
        assertTrue(service.isAvailable());
    }

    @Test
    public void testIsClustered() {
        assertTrue(service.isClustered());
    }
}
