/*
* Copyright 2017 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.rf.ide.core.execution.server;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;
import org.codehaus.jackson.map.ObjectMapper;
import org.junit.Test;
import org.rf.ide.core.execution.RobotAgentEventListener;
import org.rf.ide.core.execution.RobotAgentEventListener.RobotAgentEventsListenerException;
import com.google.common.collect.ImmutableMap;
public class AgentConnectionServerTest {
@Test
public void connectionTimeoutErrorIsHandledByListener_whenNoClientConnects() throws Exception {
final String host = "127.0.0.1";
final int port = findFreePort();
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final AgentConnectionServer server = new AgentConnectionServer(host, port, 100, TimeUnit.MILLISECONDS);
server.addStatusListener(serverStatusListener);
server.start();
verify(serverStatusListener).serverEstablished(host, port);
verify(serverStatusListener).clientConnectionTimedOut(any(SocketTimeoutException.class));
verifyNoMoreInteractions(serverStatusListener);
}
@Test
public void eventHandlingErrorIsHandledByListener_whenEventsListenerCannotHandleEvent() throws Exception {
final String host = "127.0.0.1";
final int port = findFreePort();
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final RobotAgentEventListener robotEventListener = mock(RobotAgentEventListener.class);
when(robotEventListener.isHandlingEvents()).thenReturn(true);
doThrow(RobotAgentEventsListenerException.class).when(robotEventListener).handleAgentIsReadyToStart();
final AgentConnectionServer server = new AgentConnectionServer(host, port);
server.addStatusListener(serverStatusListener);
final Thread serverThread = new Thread(() -> {
try {
server.start(robotEventListener);
} catch (final IOException e1) {
}
});
final Thread clientThread = new Thread(() -> {
try (final Socket clientSocket = new Socket(host, port);) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()))) {
final Object msgObject = ImmutableMap.of("ready_to_start", 0);
writer.write(new ObjectMapper().writeValueAsString(msgObject));
}
} catch (final Exception e) {
}
});
serverThread.start();
clientThread.start();
serverThread.join();
clientThread.join();
verify(serverStatusListener).serverEstablished(host, port);
verify(serverStatusListener).clientConnected(anyInt());
verify(serverStatusListener).clientEventHandlingError(any(RobotAgentEventsListenerException.class));
verifyNoMoreInteractions(serverStatusListener);
}
@Test
public void connectionErrorIsHandledByListener_whenInvalidMessageComesFromClient() throws Exception {
final String host = "127.0.0.1";
final int port = findFreePort();
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final RobotAgentEventListener robotEventListener = mock(RobotAgentEventListener.class);
when(robotEventListener.isHandlingEvents()).thenReturn(true);
final AgentConnectionServer server = new AgentConnectionServer(host, port);
server.addStatusListener(serverStatusListener);
final Thread serverThread = new Thread(() -> {
try {
server.start(robotEventListener);
} catch (final IOException e1) {
}
});
final Thread clientThread = new Thread(() -> {
try (final Socket clientSocket = new Socket(host, port);) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()))) {
writer.write("invalid_messge_not_a_json_mapping");
}
} catch (final Exception e) {
}
});
serverThread.start();
clientThread.start();
serverThread.join();
clientThread.join();
verify(serverStatusListener).serverEstablished(host, port);
verify(serverStatusListener).clientConnected(anyInt());
verify(serverStatusListener).clientConnectionError(any(IOException.class));
verifyNoMoreInteractions(serverStatusListener);
}
@Test
public void connectionIsProperlyHandled_whenEventListenerHandlesIncomingEvent() throws Exception {
final String host = "127.0.0.1";
final int port = findFreePort();
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final RobotAgentEventListener robotEventListener = mock(RobotAgentEventListener.class);
when(robotEventListener.isHandlingEvents()).thenReturn(true);
final AgentConnectionServer server = new AgentConnectionServer(host, port);
server.addStatusListener(serverStatusListener);
final Thread serverThread = new Thread(() -> {
try {
server.start(robotEventListener);
} catch (final IOException e1) {
}
});
final Thread clientThread = new Thread(() -> {
try (final Socket clientSocket = new Socket(host, port);) {
try (BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(clientSocket.getOutputStream()))) {
final Object msgObject = ImmutableMap.of("ready_to_start", 0);
writer.write(new ObjectMapper().writeValueAsString(msgObject));
}
} catch (final Exception e) {
}
});
serverThread.start();
clientThread.start();
serverThread.join();
clientThread.join();
verify(serverStatusListener).serverEstablished(host, port);
verify(serverStatusListener).clientConnected(anyInt());
verify(serverStatusListener).clientConnectionClosed(anyInt());
verifyNoMoreInteractions(serverStatusListener);
}
@Test(expected = BindException.class)
public void exceptionIsThrown_whenHostCannotBeReached() throws Exception {
final String host = "123456789";
final int port = findFreePort();
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final AgentConnectionServer server = new AgentConnectionServer(host, port, 100, TimeUnit.MILLISECONDS);
server.addStatusListener(serverStatusListener);
server.start();
}
@Test(expected = IllegalArgumentException.class)
public void exceptionIsThrown_whenPortIsOutOfRange() throws Exception {
final String host = "127.0.0.1";
final int port = 65536;
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final AgentConnectionServer server = new AgentConnectionServer(host, port, 100, TimeUnit.MILLISECONDS);
server.addStatusListener(serverStatusListener);
server.start();
}
@Test(timeout = 5_000)
public void deadLockDoesNotOccur_whenWaitingForServerWhichThrewExceptionDuringStarting() throws Exception {
final String host = "123456789";
final int port = findFreePort();
final AgentServerStatusListener serverStatusListener = mock(AgentServerStatusListener.class);
final AgentConnectionServer server = new AgentConnectionServer(host, port, 100, TimeUnit.MILLISECONDS);
server.addStatusListener(serverStatusListener);
final Thread serverThread = new Thread(new Runnable() {
@Override
public void run() {
try {
server.start();
} catch (final Exception e) {
}
}
});
serverThread.start();
serverThread.join();
server.waitForServerToSetup();
verifyZeroInteractions(serverStatusListener);
}
private static int findFreePort() throws IOException {
try (ServerSocket socket = new ServerSocket(0)) {
return socket.getLocalPort();
}
}
}