/FileExtraction/Java_unseen/Orange-OpenSource_fiware-cepheus/cepheus-broker/src/test/java/com/orange/cepheus/broker/RemoteRegistrationsTest.java
/*
 * Copyright (C) 2015 Orange
 *
 * This software is distributed under the terms and conditions of the 'GNU GENERAL PUBLIC LICENSE
 * Version 2' license which can be found in the file 'LICENSE.txt' in this package distribution or
 * at 'http://www.gnu.org/licenses/gpl-2.0-standalone.html'.
 */

package com.orange.cepheus.broker;

import com.orange.ngsi.client.NgsiClient;
import com.orange.ngsi.model.RegisterContext;
import com.orange.ngsi.model.RegisterContextResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.concurrent.FailureCallback;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.SuccessCallback;

import java.util.Collections;

import static com.orange.cepheus.broker.Util.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.*;
import static org.mockito.Mockito.*;

/**
 * Tests for RemoteRegistrations
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class RemoteRegistrationsTest {

    private final static String remoteBrokerUrl = "http://remoteBroker:8080";

    @Mock
    Configuration configuration;

    @Captor
    private ArgumentCaptor<SuccessCallback<RegisterContextResponse>> successCaptor;

    @Captor
    private ArgumentCaptor<FailureCallback> failureCaptor;

    @Mock
    private ListenableFuture<RegisterContextResponse> registerFuture;

    private HttpHeaders httpHeaders = new HttpHeaders();

    @Mock
    NgsiClient ngsiClient;

    @Autowired
    @InjectMocks
    protected RemoteRegistrations remoteRegistrations;

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);
        httpHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
    }

    @After
    public void resetMocks() {
        reset(ngsiClient);
        reset(configuration);
        reset(registerFuture);
    }

    @Test
    public void testRemoteRegistration() throws Exception {
        String localRegistrationId = "localRegistrationId1";
        String remoteRegistrationId = "remoteRegistrationId1";

        RegisterContext registerContext = createRegistrationContext();
        registerContext.setRegistrationId(localRegistrationId);

        // prepare mocks
        doNothing().when(registerFuture).addCallback(successCaptor.capture(), any());
        when(ngsiClient.registerContext(any(), any(), any())).thenReturn(registerFuture);
        when(ngsiClient.getRequestHeaders(any())).thenReturn(httpHeaders);
        when(configuration.getRemoteUrl()).thenReturn(remoteBrokerUrl);

        // make *the* call
        remoteRegistrations.registerContext(registerContext, localRegistrationId);

        // check that the registerId was reset on register (not sending a local registrationId to remote broker)
        assertNull(registerContext.getRegistrationId());

        // fake response from ngsi client to registerContext
        RegisterContextResponse response = new RegisterContextResponse();
        response.setRegistrationId(remoteRegistrationId);
        response.setDuration(registerContext.getDuration());
        successCaptor.getValue().onSuccess(response);

        // check NGSI client is called
        verify(ngsiClient, times(1)).registerContext(eq(remoteBrokerUrl), eq(httpHeaders), eq(registerContext));

        // check pending will not retrigger a successful register
        remoteRegistrations.registerPendingRemoteRegistrations();
        verify(ngsiClient, times(1)).registerContext(any(), any(), any());

        // check that the remote registrationId is well set
        assertEquals(remoteRegistrationId, remoteRegistrations.getRemoteRegistrationId(localRegistrationId));

        // check that remove works
        remoteRegistrations.removeRegistration(localRegistrationId);
        assertNull(remoteRegistrations.getRemoteRegistrationId(localRegistrationId));
    }

    @Test
    public void testRemoteRegistrationFailThenRetry() throws Exception {
        String localRegistrationId = "localRegistrationId1";
        String remoteRegistrationId = "remoteRegistrationId1";

        RegisterContext registerContext = createRegistrationContext();

        // prepare mocks
        doNothing().when(registerFuture).addCallback(successCaptor.capture(), failureCaptor.capture());
        when(ngsiClient.registerContext(any(), any(), any())).thenReturn(registerFuture);
        when(ngsiClient.getRequestHeaders(any())).thenReturn(httpHeaders);
        when(configuration.getRemoteUrl()).thenReturn(remoteBrokerUrl);

        // make *the* call
        remoteRegistrations.registerContext(registerContext, localRegistrationId);

        // check NGSI client is called
        verify(ngsiClient, times(1)).registerContext(eq(remoteBrokerUrl), eq(httpHeaders), eq(registerContext));

        // fake response from ngsi client to registerContext
        failureCaptor.getValue().onFailure(new RuntimeException("fail"));

        // check that no remote registration is associated on failed register
        assertNull(remoteRegistrations.getRemoteRegistrationId(localRegistrationId));

        // check register is called another time
        remoteRegistrations.registerPendingRemoteRegistrations();
        verify(ngsiClient, times(2)).registerContext(eq(remoteBrokerUrl), eq(httpHeaders), eq(registerContext));

        // fake response from ngsi client to registerContext
        RegisterContextResponse response = new RegisterContextResponse();
        response.setRegistrationId(remoteRegistrationId);
        response.setDuration(registerContext.getDuration());
        successCaptor.getValue().onSuccess(response);

        // check that the remote registrationId is well set
        assertEquals(remoteRegistrationId, remoteRegistrations.getRemoteRegistrationId(localRegistrationId));
    }

    @Test
    public void testRemoteRegistrationUpdate() throws Exception {
        String localRegistrationId = "localRegistrationId1";
        String remoteRegistrationId = "remoteRegistrationId1";

        RegisterContext registerContext = createRegistrationContext();

        // prepare mocks
        doNothing().when(registerFuture).addCallback(successCaptor.capture(), any());
        when(ngsiClient.registerContext(any(), any(), any())).thenReturn(registerFuture);
        when(ngsiClient.getRequestHeaders(any())).thenReturn(httpHeaders);
        when(configuration.getRemoteUrl()).thenReturn(remoteBrokerUrl);


        // make the call first call
        remoteRegistrations.registerContext(registerContext, localRegistrationId);

        // fake response from ngsi client to registerContext
        RegisterContextResponse response = new RegisterContextResponse();
        response.setRegistrationId(remoteRegistrationId);
        response.setDuration(registerContext.getDuration());
        successCaptor.getValue().onSuccess(response);

        // rechecks
        verify(ngsiClient, times(1)).registerContext(eq(remoteBrokerUrl), eq(httpHeaders), eq(registerContext));
        assertEquals(remoteRegistrationId, remoteRegistrations.getRemoteRegistrationId(localRegistrationId));

        // Prepare a new registerContext
        RegisterContext registerContextUpdate = createRegistrationContext();
        registerContext.setRegistrationId(localRegistrationId);

        // trigger an update of the register
        remoteRegistrations.registerContext(registerContextUpdate, localRegistrationId);

        // check that the registerId was reset to previous remote registrationId
        assertEquals(remoteRegistrationId, registerContextUpdate.getRegistrationId());

        // fake response from ngsi client to registerContext
        RegisterContextResponse response2 = new RegisterContextResponse();
        response2.setRegistrationId(remoteRegistrationId);
        response2.setDuration(registerContextUpdate.getDuration());
        successCaptor.getValue().onSuccess(response2);

        // rechecks
        verify(ngsiClient, times(1)).registerContext(eq(remoteBrokerUrl), eq(httpHeaders), eq(registerContextUpdate));
        assertEquals(remoteRegistrationId, remoteRegistrations.getRemoteRegistrationId(localRegistrationId));
    }

    @Test
    public void testRemoteRegistrationNoBroker() throws Exception {
        String localRegistrationId = "localRegistrationId1";

        RegisterContext registerContext = createRegistrationContext();

        // declare no broker
        when(configuration.getRemoteUrl()).thenReturn(null);

        // make *the* call
        remoteRegistrations.registerContext(registerContext, localRegistrationId);

        // check no remote was called
        verify(ngsiClient, never()).registerContext(any(), any(), any());
        assertNull(remoteRegistrations.getRemoteRegistrationId(localRegistrationId));
    }

    @Test
    public void testRemoteRegistrationNoUrlBroker() throws Exception {
        String localRegistrationId = "localRegistrationId1";

        RegisterContext registerContext = createRegistrationContext();

        // declare no broker
        when(configuration.getRemoteUrl()).thenReturn(null);

        // make *the* call
        remoteRegistrations.registerContext(registerContext, localRegistrationId);

        // check no remote was called
        verify(ngsiClient, never()).registerContext(any(), any(), any());
        assertNull(remoteRegistrations.getRemoteRegistrationId(localRegistrationId));
    }

    @Test
    public void testRemoteRegistrationEmptyUrlBroker() throws Exception {
        String localRegistrationId = "localRegistrationId1";

        RegisterContext registerContext = createRegistrationContext();

        // declare no broker
        when(configuration.getRemoteUrl()).thenReturn("");

        // make *the* call
        remoteRegistrations.registerContext(registerContext, localRegistrationId);

        // check no remote was called
        verify(ngsiClient, never()).registerContext(any(), any(), any());
        assertNull(remoteRegistrations.getRemoteRegistrationId(localRegistrationId));
    }
}
