/*
 * Copyright Avaya Inc., All Rights Reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF Avaya Inc.
 *
 * The copyright notice above does not evidence any actual or intended
 * publication of such source code.
 *
 * Some third-party source code components may have been modified from their
 * original versions by Avaya Inc.
 *
 * The modifications are Copyright Avaya Inc., All Rights Reserved.
 */

package com.avaya.oceanalytics.openinterface.websocketclient.subscription;


import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.internal.util.collections.Sets;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

/**
 * Test cases for the {@link SubscriptionManager} class.
 *
 * @author Ivan Kovalev
 */
public class TestSubscriptionManager {

    private static final String ROUTINGSERVICE_PRODUCER_ID = "RoutingService_SoD_3.5";
    private static final Set<String> SUBSCRIPTIONS = Sets.newSet(ROUTINGSERVICE_PRODUCER_ID, "AgentByAccount_SoD_3.5");

    @Mock
    private ConcurrentMap<String, Subscription> internalMap;
    @Mock
    private Subscription subscription;
    private SubscriptionManager subscriptionManager;

    @BeforeClass
    public static void init() throws Exception {
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        Field subscriptionByMeasureField = SubscriptionManager.class.getDeclaredField("subscriptionByProducer");
        modifiersField.setInt(subscriptionByMeasureField, subscriptionByMeasureField.getModifiers() & ~Modifier.FINAL);
    }

    @Before
    public void setup() throws Exception {
        MockitoAnnotations.initMocks(this);
        subscriptionManager = new SubscriptionManager();
        when(internalMap.get(ROUTINGSERVICE_PRODUCER_ID)).thenReturn(subscription);
        when(internalMap.remove(ROUTINGSERVICE_PRODUCER_ID)).thenReturn(subscription);
        when(internalMap.keySet()).thenReturn(SUBSCRIPTIONS);
        Field subscriptionByMeasureField = SubscriptionManager.class.getDeclaredField("subscriptionByProducer");
        subscriptionByMeasureField.setAccessible(true);
        subscriptionByMeasureField.set(subscriptionManager, internalMap);
    }

    @Test
    public void testAssociate() {
        subscriptionManager.associate(ROUTINGSERVICE_PRODUCER_ID, subscription);
        verify(internalMap, times(1)).put(eq(ROUTINGSERVICE_PRODUCER_ID), any(Subscription.class));
    }

    @Test
    public void testDissociate() {
        assertSame(subscription, subscriptionManager.dissociate(ROUTINGSERVICE_PRODUCER_ID));
        verify(internalMap, times(1)).remove(eq(ROUTINGSERVICE_PRODUCER_ID));
    }

    @Test
    public void testGetSubscription() {
        assertSame(subscription, subscriptionManager.getSubscription(ROUTINGSERVICE_PRODUCER_ID));
        verify(internalMap, times(1)).get(eq(ROUTINGSERVICE_PRODUCER_ID));
    }

    @Test(expected = UnsupportedOperationException.class)
    public void testGetAllSubscriptions() {
        Set<String> subscriptions = subscriptionManager.getAllSubscriptions();
        assertNotNull(subscriptions);
        assertEquals(SUBSCRIPTIONS.size(), subscriptions.size());
        subscriptions.forEach(sub -> assertTrue(SUBSCRIPTIONS.contains(sub)));
        verify(internalMap, times(1)).keySet();
        subscriptions.iterator().remove();
    }

    @Test
    public void testDestroy() {
        subscriptionManager.destroy();
        verify(internalMap, times(1)).clear();
    }

    @Test(expected = IllegalStateException.class)
    public void testCheckState() {
        subscriptionManager.destroy();
        verify(internalMap, times(1)).clear();
        subscriptionManager.associate(ROUTINGSERVICE_PRODUCER_ID, subscription);
    }
}
