package org.f1x.v1;
import org.f1x.SessionIDBean;
import org.f1x.TestCommon;
import org.f1x.api.FixAcceptorSettings;
import org.f1x.api.session.SessionManager;
import org.f1x.util.AsciiUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.*;
public class Test_SessionAcceptorWrapper extends TestCommon {
private SessionAcceptorWrapper wrapper;
private int onStopInvocationCount;
private SessionManager manager;
// Mocks
private FixSessionAcceptor acceptor;
private Socket socket;
@Before
public void init() {
onStopInvocationCount = 0;
manager = new SimpleSessionManager();
acceptor = mock(FixSessionAcceptor.class);
when(acceptor.getSettings()).thenReturn(new FixAcceptorSettings());
wrapper = new SessionAcceptorWrapper(1024, 500, manager) {
@Override
protected void onStop() {
onStopInvocationCount++;
assertWrapperStateOnStop();
}
private void assertWrapperStateOnStop() {
assertNull(this.socket);
assertEquals(new SessionIDBean(), sessionID);
}
};
socket = mock(Socket.class);
wrapper.setSocket(socket);
}
@Test
public void testEmptyMessage() throws Exception {
simulateMessageOnSocketRead("");
simulateWrapperRun();
assertThatAcceptorWasNotStarted();
}
@Test(timeout = 300)
public void testSocketException() throws IOException {
throwExceptionOnSocketRead(SocketException.class);
simulateWrapperRun();
assertThatAcceptorWasNotStarted();
}
@Test(timeout = 300)
public void testSocketTimeoutException() throws IOException {
throwExceptionOnSocketRead(SocketTimeoutException.class);
simulateWrapperRun();
assertThatAcceptorWasNotStarted();
}
@Test
public void testInvalidLogon() throws IOException {
String logonWithoutBodyLength = "8=FIX.4.4|35=A|34=1|49=SC|50=SS|52=20140101-10:10:10.100|56=TC|57=TS|98=0|108=30|141=Y|383=8192|10=080|";
simulateMessageOnSocketRead(logonWithoutBodyLength);
simulateWrapperRun();
assertThatAcceptorWasNotStarted();
}
@Test
public void testVeryLongLogonMessage() throws IOException {
String veryLongLogon = "8=FIX.4.4|9="
+ (acceptor.getSettings().getMaxInboundMessageSize() + 1)
+ "|35=A|34=1|49=SC|50=SS|52=20140101-10:10:10.100|56=TC|57=TS|98=0|108=30|141=Y|383=8192|10=080|";
simulateMessageOnSocketRead(veryLongLogon);
simulateWrapperRun();
assertThatAcceptorWasNotStarted();
}
@Test
public void testLogonWithUnregisteredSessionID() throws IOException {
String logon = "8=FIX.4.4|9=82|35=A|34=1|49=SC|50=SS|52=20140101-10:10:10.100|56=TC|57=TS|98=0|108=30|141=Y|383=8192|10=080|NEXT MESSAGE";
simulateMessageOnSocketRead(logon);
simulateWrapperRun();
assertThatAcceptorWasNotStarted();
}
@Test
public void testLogonWithRegisteredSessionID() throws IOException {
String logon = "8=FIX.4.4|9=74|35=A|34=1|49=SC|52=20140101-10:10:10.100|56=TC|98=0|108=30|141=Y|383=8192|10=080|NEXT MESSAGE";
simulateMessageOnSocketRead(logon);
when(acceptor.getSessionID()).thenReturn(new SessionIDBean("TC", "SC"));
manager.addSession(acceptor);
simulateWrapperRun();
assertThatAcceptorWasStarted(logon);
}
@After
public void assertOnStopInvocation() {
assertEquals(1, onStopInvocationCount);
}
private void throwExceptionOnSocketRead(Class<? extends Throwable> exceptionClass) throws IOException {
InputStream in = mock(InputStream.class);
when(in.read(any(byte[].class), anyInt(), anyInt())).thenThrow(exceptionClass);
when(socket.getInputStream()).thenReturn(in);
}
private void simulateMessageOnSocketRead(String message) throws IOException {
message = message.replace('|', '\u0001');
ByteArrayInputStream simulatedInputStream = new ByteArrayInputStream(AsciiUtils.getBytes(message));
when(socket.getInputStream()).thenReturn(simulatedInputStream);
}
private void simulateWrapperRun() {
wrapper.run();
}
private void assertThatAcceptorWasNotStarted() throws IOException {
verify(acceptor, never()).run(any(byte[].class), anyInt());
verify(socket).close();
}
private void assertThatAcceptorWasStarted(final String expectedMessage) {
verify(acceptor).run(argThat(new BaseMatcher<byte[]>() {
private final byte[] expectedByteMessage = AsciiUtils.getBytes(expectedMessage.replace('|', '\u0001'));
@Override
public boolean matches(Object o) {
if (o instanceof byte[]) {
byte[] actualByteMessage = (byte[]) o;
for (int index = 0; index < expectedByteMessage.length; index++)
if (expectedByteMessage[index] != actualByteMessage[index])
return false;
return true;
} else {
return false;
}
}
@Override
public void describeTo(Description description) {
description.appendText(Arrays.toString(expectedByteMessage));
}
}), eq(expectedMessage.length()));
}
}