package org.f1x.v1; import org.f1x.SessionIDBean; import org.f1x.TestCommon; import org.f1x.api.message.MessageParser; import org.f1x.api.message.fields.FixTags; import org.f1x.api.session.SessionEventListener; import org.f1x.api.session.SessionID; import org.f1x.api.session.SessionState; import org.f1x.api.session.SessionStatus; import org.f1x.io.PredefinedInputChannel; import org.f1x.io.TextOutputChannel; import org.f1x.store.InMemoryMessageStore; import org.f1x.store.MessageStore; import org.f1x.util.AsciiUtils; import org.f1x.util.StoredTimeSource; import org.f1x.util.TimeSource; import org.f1x.v1.state.TestSessionState; import org.junit.*; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Test_FixCommunicatorProcessingMessages extends TestCommon { protected static final String LOGON = "8=FIX.4.4|9=84|35=A|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|98=0|108=30|141=N|383=8192|10=209|"; protected static final String LOGOUT = "8=FIX.4.4|9=89|35=5|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|58=Responding to Logout request|10=101|"; protected static final String HEARTBEAT = "8=FIX.4.4|9=70|35=0|34=2|49=RECEIVER|52=20140101-10:10:10.100|56=SENDER|112=TEST#123|10=024|"; protected static final String TEST_REQUEST = "8=FIX.4.4|9=67|35=1|34=2|49=RECEIVER|52=20140101-10:10:10.100|56=SENDER|112=TEST123|10=245|"; protected static final String REJECT = "8=FIX.4.4|9=79|35=3|34=5|49=RECEIVER|52=20140101-10:10:10.100|56=SENDER|45=123|373=1|58=Cause|10=053|"; protected static final String RESEND_REQUEST = "8=FIX.4.4|9=67|35=2|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=5|16=10|10=136|"; protected static final String SEQUENCE_RESET = "8=FIX.4.4|9=72|35=4|34=776|49=RECEIVER|52=20140101-10:10:10.100|56=SENDER|36=777|123=N|10=043|"; protected static final String NEW_ORDER = "8=FIX.4.4|9=78|35=D|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|1=Account|11=OrderID|10=053|"; private static final SessionID SESSION_ID = new SessionIDBean("RECEIVER", "SENDER"); private static final TimeSource TIME_SOURCE = new StoredTimeSource(0); private final List<SessionStatus> sessionStatusFlow = new ArrayList<>(); private final List<String> errors = new ArrayList<>(); private final SessionState sessionState = new TestSessionState(); private final MessageStore messageStore = new InMemoryMessageStore(1 << 15); private FixCommunicator communicator; @Before public void init() { communicator = new TestFixCommunicator(SESSION_ID, TIME_SOURCE) { @Override protected void processInboundAppMessage(CharSequence msgType, int msgSeqNum, boolean possDup, MessageParser parser) throws IOException { sendHeartbeat(null); // just increases sender seq num } @Override protected void errorProcessingMessage(String errorText, Exception e, boolean logStackTrace) { if (e != ConnectionProblemException.NO_SOCKET_DATA) errors.add(e.toString()); super.errorProcessingMessage(errorText, e, logStackTrace); } }; communicator.setEventListener(new SessionEventListener() { @Override public void onStatusChanged(SessionID sessionID, SessionStatus oldStatus, SessionStatus newStatus) { sessionStatusFlow.add(newStatus); } }); communicator.setSessionState(sessionState); communicator.setMessageStore(messageStore); } @After public void close() { messageStore.clean(); sessionState.resetNextSeqNums(); sessionStatusFlow.clear(); errors.clear(); } // ---------- LOGON ---------- @Test public void testLogonWithoutHeartbeatInterval() { String inboundLogon = "8=FIX.4.4|9=57|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=020|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.SocketConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(1, 1); assertErrorsOccurred(InvalidFixMessageException.NO_HEARTBEAT_INTERVAL); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.Disconnected ); } @Test public void testLogonMismatchingHeartbeatInterval() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=11|10=020|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.SocketConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(1, 1); assertErrorsOccurred(ConnectionProblemException.HEARTBEAT_INTERVAL_MISMATCH); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.Disconnected ); } @Test public void testLogonWithResetSeqNumAndSeqNumMoreOne() { String inboundLogon = "8=FIX.4.4|9=70|35=A|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|141=Y|10=020|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.SocketConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(1, 1); assertErrorsOccurred(InvalidFixMessageException.MSG_SEQ_NUM_MUST_BE_ONE); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.Disconnected ); } @Test public void testLogonWithResetSeqNum() { String inboundLogon = "8=FIX.4.4|9=70|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|141=Y|10=020|"; String expectedOutboundLogon = "8=FIX.4.4|9=84|35=A|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|98=0|108=30|141=Y|383=8192|10=216|"; setSessionStatus(SessionStatus.SocketConnected); setNextSeqNums(100, 100); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundLogon); assertNextSeqNums(2, 2); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.ReceivedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testLogonWithSeqNumLessExpected() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=2|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|10=020|"; String expectedOutboundMessages = ""; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.SocketConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(5, 5); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.Disconnected ); } @Test public void testLogon() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|10=020|"; String expectedOutboundLogon = "8=FIX.4.4|9=84|35=A|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|98=0|108=30|141=N|383=8192|10=209|"; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.SocketConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundLogon); assertNextSeqNums(6, 6); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.ReceivedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testLogonWithTargetSeqNumMoreExpected() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|10=020|"; String expectedOutboundLogon = "8=FIX.4.4|9=84|35=A|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|98=0|108=30|141=N|383=8192|10=205|"; String expectedResendRequest = "8=FIX.4.4|9=66|35=2|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=1|16=4|10=083|"; setSessionStatus(SessionStatus.SocketConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundLogon, expectedResendRequest); assertNextSeqNums(6, 3); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.SocketConnected, SessionStatus.ReceivedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testLogonResponse() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|10=020|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.InitiatedLogon); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(2, 1); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } /** Same as above but acceptor responds with LOGON that has 141=Y */ @Ignore @Test public void testLogonResponseResetSequenceNumbers() { String inboundLogon = "8=FIX.4.4|9=70|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|141=Y|108=30|10=020|"; String expectedOutboundMessages = ""; setNextSeqNums(100, 100); setSessionStatus(SessionStatus.InitiatedLogon); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(2, 2); // TODO: Validate in the spec assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testLogonResponseWithSeqNumMoreExpected() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|10=020|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=1|16=4|10=082|"; setSessionStatus(SessionStatus.InitiatedLogon); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundResendRequest); assertNextSeqNums(6, 2); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testInSessionLogonWithoutSeqReset() { String inboundLogon = "8=FIX.4.4|9=64|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|10=020|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(1, 1); assertErrorsOccurred(InvalidFixMessageException.IN_SESSION_LOGON_MESSAGE_WITHOUT_MSG_SEQ_RESET_NOT_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } /** This test verifies that system is capable of initiating a sequence number reset during an existing FIX session */ @Test public void testInSessionSequenceNumberResetViaLOGON() { setNextSeqNums(100, 100); setSessionStatus(SessionStatus.ApplicationConnected); // Once the Heartbeat has been received, the initiator should send a Logon with ResetSeqNumFlag set to Y and with MsgSeqNum of 1. // The acceptor should respond with a Logon with ResetSeqNumFlag set to Y and with MsgSeqNum of 1. String inboundLogon = "8=FIX.4.4|9=70|35=A|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|108=30|141=Y|10=020|"; String expectedOutboundLogon = "8=FIX.4.4|9=84|35=A|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|98=0|108=30|141=Y|383=8192|10=216|"; String actualOutboundMessages = simulateProcessing(inboundLogon); assertMessages(actualOutboundMessages, expectedOutboundLogon); assertNextSeqNums(2, 2); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } // ---------- LOGOUT ---------- @Test public void testLogout() { String inboundLogout = "8=FIX.4.4|9=57|35=5|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=020|"; String expectedOutboundLogout = "8=FIX.4.4|9=92|35=5|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|58=Responding to LOGOUT(5) request|10=069|"; setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundLogout); assertNextSeqNums(2, 2); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.InitiatedLogout, SessionStatus.SocketConnected, SessionStatus.Disconnected ); } @Test public void testLogoutWithSeqNumMoreExpected() { String inboundLogout = "8=FIX.4.4|9=57|35=5|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=020|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=1|16=4|10=082|"; String expectedOutboundLogout = "8=FIX.4.4|9=92|35=5|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|58=Responding to LOGOUT(5) request|10=070|"; setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundResendRequest, expectedOutboundLogout); assertNextSeqNums(6, 3); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.InitiatedLogout, /// Per FIX spec we keep connection open to allow LOGOUT initiator to fill gaps// SessionStatus.SocketConnected, SessionStatus.Disconnected ); } @Test public void testLogoutWithSeqNumLessExpected() { String inboundLogout = "8=FIX.4.4|9=57|35=5|34=1|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=020|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.ApplicationConnected); setNextTargetSeqNum(5); String actualOutboundMessages = simulateProcessing(inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(5, 1); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testLogoutResponseWithSeqNumMoreExpected() { String inboundLogout = "8=FIX.4.4|9=57|35=5|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=024|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.InitiatedLogout); String actualOutboundMessages = simulateProcessing(inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(1, 1); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogout, SessionStatus.Disconnected ); } /** We initiated logout but other side detected a gap and requested resend before responding with LOGOUT */ @Test public void testResendWhileLogout() { String inboundResend = "8=FIX.4.4|9=66|35=2|34=2|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|7=1|16=0|10=136|"; // Pls resend 1... String inboundLogout = "8=FIX.4.4|9=57|35=5|34=3|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=024|"; String expectedOutboundGapFill = "8=FIX.4.4|9=73|35=4|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=4|123=Y|10=217|"; // Gap fill [1..3] setSessionStatus(SessionStatus.InitiatedLogout); fillMessageStore(1, LOGON, HEARTBEAT, TEST_REQUEST); // Next SenderCompID=4 setNextSeqNums(2, 4); String actualOutboundMessages = simulateProcessing(inboundResend, inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundGapFill); assertNextSeqNums(4, 4); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogout, SessionStatus.Disconnected ); } /** Same as above, but this time we have to resend REJECT */ @Test public void testResendWhileLogout2() { String inboundResend = "8=FIX.4.4|9=66|35=2|34=2|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|7=1|16=0|10=136|"; // Pls resend 1... String inboundLogout = "8=FIX.4.4|9=57|35=5|34=3|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=024|"; String expectedOutboundGapFill1 = "8=FIX.4.4|9=73|35=4|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=2|123=Y|10=215|"; // Gap fill [1..1] String expectedRejectRebroadcast = "8=FIX.4.4|9=110|35=3|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|45=123|373=1|58=Cause|10=189|"; // REJECT String expectedOutboundGapFill2 = "8=FIX.4.4|9=73|35=4|34=3|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=4|123=Y|10=219|"; // Gap fill [3..3] setSessionStatus(SessionStatus.InitiatedLogout); fillMessageStore(1, LOGON, REJECT, TEST_REQUEST); // Next SenderCompID=4 setNextSeqNums(2, 4); String actualOutboundMessages = simulateProcessing(inboundResend, inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundGapFill1, expectedRejectRebroadcast, expectedOutboundGapFill2); assertNextSeqNums(4, 4); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogout, SessionStatus.Disconnected ); } @Test public void testMultipleGaps() { String inboundLogon = "8=FIX.4.4|9=84|35=A|34=1|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|98=0|108=30|141=N|383=8192|10=209|"; String inboundAppMsg1 = "8=FIX.4.4|9=107|35=h|34=10|49=SENDER|52=20140605-17:13:28.568|56=RECEIVER|335=242131811009569|336=SESS#1401988408564|340=2|10=152|"; String inboundAppMsg2 = "8=FIX.4.4|9=107|35=h|34=20|49=SENDER|52=20140605-17:13:28.568|56=RECEIVER|335=242131811009569|336=SESS#1401988408564|340=2|10=152|"; String expectedOutboundResend1 = "8=FIX.4.4|9=66|35=2|34=1|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=2|16=8|10=087|"; String expectedOutboundAppMsg1 = "8=FIX.4.4|9=57|35=0|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|10=210|"; String expectedOutboundResend2 = "8=FIX.4.4|9=68|35=2|34=3|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=11|16=18|10=188|"; String expectedOutboundAppMsg2 = "8=FIX.4.4|9=57|35=0|34=4|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|10=212|"; setSessionStatus(SessionStatus.InitiatedLogon); setNextSeqNums(1, 1); String actualOutboundMessages = simulateProcessing(inboundLogon, inboundAppMsg1, inboundAppMsg2); assertMessages(actualOutboundMessages, expectedOutboundResend1, expectedOutboundAppMsg1, expectedOutboundResend2, expectedOutboundAppMsg2); assertNextSeqNums(21, 5); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testLogoutResponseWithSeqNumMoreExpectedOnInvalidLogon() { String inboundLogout = "8=FIX.4.4|9=57|35=5|34=5|49=SENDER|52=20140522-12:07:39.552|56=RECEIVER|10=024|"; String expectedOutboundMessages = ""; setSessionStatus(SessionStatus.InitiatedLogon); String actualOutboundMessages = simulateProcessing(inboundLogout); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(1, 1); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogon, SessionStatus.Disconnected ); } // ---------- HEARTBEAT ---------- @Test public void testHeartbeat() { String inboundHeartbeat = "8=FIX.4.4|9=70|35=0|34=2|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|112=TEST#123|10=024|"; String expectedOutboundMessages = ""; setNextSeqNums(2, 2); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundHeartbeat); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(3, 2); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testHeartbeatWithSeqNumMoreExpected() { String inboundHeartbeat = "8=FIX.4.4|9=70|35=0|34=3|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|112=TEST#123|10=024|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=2|16=2|10=082|"; setNextSeqNums(2, 2); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundHeartbeat); assertMessages(actualOutboundMessages, expectedOutboundResendRequest); assertNextSeqNums(4, 3); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testHeartbeatWithSeqNumLessExpected() { String inboundHeartbeat = "8=FIX.4.4|9=70|35=0|34=1|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|112=TEST#123|10=024|"; String expectedOutboundMessages = ""; setNextSeqNums(3, 3); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundHeartbeat); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(3, 3); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } // ---------- TEST REQUEST ---------- @Test public void testTestRequest() { String inboundTestRequest = "8=FIX.4.4|9=69|35=1|34=2|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|112=TEST123|10=245|"; String expectedOutboundHeartbeat = "8=FIX.4.4|9=69|35=0|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|112=TEST123|10=125|"; setNextSeqNums(2, 2); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundHeartbeat); assertNextSeqNums(3, 3); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testTestRequestWithSeqNumMoreExpected() { String inboundTestRequest = "8=FIX.4.4|9=69|35=1|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|112=TEST123|10=245|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=2|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=2|16=4|10=084|"; setNextSeqNums(2, 2); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundResendRequest); assertNextSeqNums(6, 3); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testTestRequestWithSeqNumLessExpected() { String inboundTestRequest = "8=FIX.4.4|9=69|35=1|34=1|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|112=TEST123|10=245|"; String expectedOutboundMessages = ""; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(5, 5); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } // ---------- SEQUENCE RESET ---------- @Test public void testSequenceResetResetWithSeqNumLessExpected() { String inboundTestRequest = "8=FIX.4.4|9=72|35=4|34=776|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|36=777|123=N|10=043|"; String expectedOutboundMessages = ""; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(777, 5); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testSequenceResetToValueLessExpected() { String inboundTestRequest = "8=FIX.4.4|9=72|35=4|34=776|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|36=777|123=N|10=043|"; String expectedOutboundReject = "8=FIX.4.4|9=125|35=3|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|45=776|373=6|58=SequenceReset can only increase the sequence number|10=104|"; setNextSeqNums(5000, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundReject); assertNextSeqNums(5000, 6); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testSequenceResetGapFill() { String inboundTestRequest = "8=FIX.4.4|9=75|35=4|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|43=N|36=100|123=Y|10=079|"; String expectedOutboundMessages = ""; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(100, 5); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testSequenceResetGapFillWithSeqNumMoreExpected() { String inboundResetRequest = "8=FIX.4.4|9=76|35=4|34=10|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|43=N|36=100|123=Y|10=079|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=5|16=9|10=095|"; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundResetRequest); // MsgSeqNum=10 instead of 5 assertMessages(actualOutboundMessages, expectedOutboundResendRequest); assertNextSeqNums(100, 6); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } /** Same as above but this time inbound RESEND marked as PossDupFlag=Y (we should ignore it) */ @Test public void testSequenceResetGapFillWithSeqNumMoreExpectedPossDup() { String inboundResetRequest = "8=FIX.4.4|9=76|35=4|34=10|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|43=Y|36=100|123=Y|10=079|"; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundResetRequest); // MsgSeqNum=10 instead of 5 assertMessages(actualOutboundMessages); assertNextSeqNums(5, 5); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testSequenceResetGapFillWithSeqNumLessExpected() { String inboundSeqResetGapFillRequest = "8=FIX.4.4|9=76|35=4|34=10|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|43=N|36=100|123=Y|10=079|"; String expectedOutboundMessages = ""; setNextSeqNums(15, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundSeqResetGapFillRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(15, 5); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } // ---------- REJECT ---------- @Test public void testReject() { String inboundTestRequest = "8=FIX.4.4|9=79|35=3|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|45=123|373=1|58=Cause|10=053|"; String expectedOutboundMessages = ""; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(6, 5); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testRejectWithSeqNumMoreExpected() { String inboundTestRequest = "8=FIX.4.4|9=80|35=3|34=10|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|45=123|373=1|58=Cause|10=053|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=5|16=9|10=095|"; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundResendRequest); assertNextSeqNums(11, 6); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testRejectWithSeqNumLessExpected() { String inboundTestRequest = "8=FIX.4.4|9=79|35=3|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|45=123|373=1|58=Cause|10=053|"; String expectedOutboundMessages = ""; setNextSeqNums(15, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(15, 5); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } // ---------- APPLICATION MESSAGES ---------- @Test public void testNewOrder() { String inboundTestRequest = "8=FIX.4.4|9=79|35=D|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|45=123|373=1|58=Cause|10=053|"; String expectedOutboundHeartbeat = "8=FIX.4.4|9=57|35=0|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|10=213|"; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundHeartbeat); assertNextSeqNums(6, 6); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testNewOrderWithSeqNumMoreExpected() { String inboundTestRequest = "8=FIX.4.4|9=80|35=D|34=10|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|45=123|373=1|58=Cause|10=053|"; String expectedOutboundResendRequest = "8=FIX.4.4|9=66|35=2|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=5|16=8|10=094|"; String expectedOutboundTestResponse = "8=FIX.4.4|9=57|35=0|34=6|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|10=214|"; setNextSeqNums(5, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundResendRequest, expectedOutboundTestResponse); assertNextSeqNums(11, 7); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testNewOrderWithSeqNumLessExpected() { String inboundTestRequest = "8=FIX.4.4|9=79|35=D|34=5|49=SENDER|52=20140101-10:10:10.100|56=RECEIVER|45=123|373=1|58=Cause|10=053|"; String expectedOutboundMessages = ""; setNextSeqNums(15, 5); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(15, 5); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } // ---------- RESEND REQUEST ---------- @Test public void testResendRequestForInfinity() { String inboundTestRequest = "8=FIX.4.4|9=66|35=2|34=5|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|7=5|16=0|10=136|"; String firstExpectedOutboundGapFill = "8=FIX.4.4|9=73|35=4|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=9|123=Y|10=226|"; String expectedOutboundReject = "8=FIX.4.4|9=110|35=3|34=9|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|45=123|373=1|58=Cause|10=196|"; String secondExpectedOutboundGapFill = "8=FIX.4.4|9=75|35=4|34=10|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=11|123=Y|10=057|"; String expectedOutboundNewOrder = "8=FIX.4.4|9=110|35=D|34=11|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|1=Account|11=OrderID|10=126|"; String thirdExpectedOutboundGapFill = "8=FIX.4.4|9=75|35=4|34=12|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=15|123=Y|10=063|"; setNextSeqNums(5, 15); setSessionStatus(SessionStatus.ApplicationConnected); fillMessageStore(5, LOGON, HEARTBEAT, TEST_REQUEST, RESEND_REQUEST, REJECT, SEQUENCE_RESET, NEW_ORDER, LOGOUT); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, firstExpectedOutboundGapFill, expectedOutboundReject, secondExpectedOutboundGapFill, expectedOutboundNewOrder, thirdExpectedOutboundGapFill); assertNextSeqNums(6, 15); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testResendRequest() { String inboundTestRequest = "8=FIX.4.4|9=67|35=2|34=5|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|7=5|16=20|10=136|"; String firstExpectedOutboundGapFill = "8=FIX.4.4|9=73|35=4|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=9|123=Y|10=226|"; String expectedOutboundReject = "8=FIX.4.4|9=110|35=3|34=9|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|45=123|373=1|58=Cause|10=196|"; String secondExpectedOutboundGapFill = "8=FIX.4.4|9=75|35=4|34=10|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=11|123=Y|10=057|"; String expectedOutboundNewOrder = "8=FIX.4.4|9=110|35=D|34=11|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|1=Account|11=OrderID|10=126|"; String thirdExpectedOutboundGapFill = "8=FIX.4.4|9=75|35=4|34=12|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=21|123=Y|10=060|"; setNextSeqNums(5, 25); setSessionStatus(SessionStatus.ApplicationConnected); fillMessageStore(5, LOGON, HEARTBEAT, TEST_REQUEST, RESEND_REQUEST, REJECT, SEQUENCE_RESET, NEW_ORDER, LOGOUT); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, firstExpectedOutboundGapFill, expectedOutboundReject, secondExpectedOutboundGapFill, expectedOutboundNewOrder, thirdExpectedOutboundGapFill); assertNextSeqNums(6, 25); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } /** In this test we receive LOGON immediately followed by an app message. Problem is that LOGON has higher than expected sequence number (a gap). Test ensures that we request single RESEND request */ @Test public void testLogonPlusAppMessageAndMessageGap() { // FIX Acceptor that we simulate always sends SessionStatus(35=h) right after LOGON // Let's assume that during the PREVIOUS session Acceptor sent: // 8=FIX.4.4|9=84|35=A|34=1|49=.. // 8=FIX.4.3|9=113|35=h|34=2|49=.. // 8=FIX.4.3|9=113|35=5|34=3|49=.. setNextSeqNums(3, 4); // We stored targetNext as 3 but they sent LOGOUT and actual nextTarget will be 4 setSessionStatus(SessionStatus.InitiatedLogon); fillMessageStore(1, LOGON, TEST_REQUEST, LOGOUT); // NEW SESSION String inboundLogon = "8=FIX.4.4|9=84|35=A|34=4|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|98=0|108=30|141=N|383=8192|10=209|"; String inboundSessionStatus = "8=FIX.4.4|9=106|35=h|34=5|49=SENDER|52=20140605-17:13:28.568|56=RECEIVER|335=242131811009569|336=SESS#1401988408564|340=2|10=152|"; String actualOutboundMessages = simulateProcessing(inboundLogon, inboundSessionStatus); // assert state becomes ApplicationConnected String expectedLogonConfirmation = "8=FIX.4.4|9=66|35=2|34=4|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=3|16=3|10=086|"; String expectedSessionStatResponse = "8=FIX.4.4|9=57|35=0|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|10=213|"; assertMessages(actualOutboundMessages, expectedLogonConfirmation, expectedSessionStatResponse); assertNextSeqNums(6, 6); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.InitiatedLogon, SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testResendRequestWithSeqNumLessExpected() { String inboundTestRequest = "8=FIX.4.4|9=67|35=2|34=2|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|7=5|16=20|10=136|"; String expectedOutboundMessages = ""; setNextSeqNums(5, 25); setSessionStatus(SessionStatus.ApplicationConnected); String actualOutboundMessages = simulateProcessing(inboundTestRequest); assertMessages(actualOutboundMessages, expectedOutboundMessages); assertNextSeqNums(5, 25); assertErrorsOccurred(InvalidFixMessageException.TARGET_MSG_SEQ_NUM_LESS_EXPECTED); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } @Test public void testResendRequestWithSeqNumMoreExpected() { String inboundResendRequest = "8=FIX.4.4|9=67|35=2|34=9|49=SENDER|52=19700101-00:00:00.000|56=RECEIVER|7=5|16=20|10=136|"; String firstExpectedOutboundGapFill = "8=FIX.4.4|9=73|35=4|34=5|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=9|123=Y|10=226|"; String expectedOutboundReject = "8=FIX.4.4|9=110|35=3|34=9|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|45=123|373=1|58=Cause|10=196|"; String secondExpectedOutboundGapFill = "8=FIX.4.4|9=75|35=4|34=10|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=11|123=Y|10=057|"; String expectedOutboundNewOrder = "8=FIX.4.4|9=110|35=D|34=11|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|122=20140101-10:10:10.100|1=Account|11=OrderID|10=126|"; String thirdExpectedOutboundGapFill = "8=FIX.4.4|9=75|35=4|34=12|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|43=Y|36=21|123=Y|10=060|"; String expectedResendRequest = "8=FIX.4.4|9=67|35=2|34=25|49=RECEIVER|52=19700101-00:00:00.000|56=SENDER|7=5|16=8|10=145|"; setNextSeqNums(5, 25); setSessionStatus(SessionStatus.ApplicationConnected); fillMessageStore(5, LOGON, HEARTBEAT, TEST_REQUEST, RESEND_REQUEST, REJECT, SEQUENCE_RESET, NEW_ORDER, LOGOUT); String actualOutboundMessages = simulateProcessing(inboundResendRequest); assertMessages(actualOutboundMessages, firstExpectedOutboundGapFill, expectedOutboundReject, secondExpectedOutboundGapFill, expectedOutboundNewOrder, thirdExpectedOutboundGapFill, expectedResendRequest); assertNextSeqNums(10, 26); assertNoErrorsOccurred(); assertSessionStatusFlow( SessionStatus.ApplicationConnected, SessionStatus.Disconnected ); } protected void setSessionStatus(SessionStatus status) { communicator.setSessionStatus(status); } protected void setNextSeqNums(int target, int sender) { setNextTargetSeqNum(target); setNextSenderSeqNum(sender); } protected void setNextTargetSeqNum(int msgSeqNum) { sessionState.setNextTargetSeqNum(msgSeqNum); } protected void setNextSenderSeqNum(int msgSeqNum) { sessionState.setNextSenderSeqNum(msgSeqNum); } protected void assertErrorsOccurred(Throwable... errors) { String[] stringErrors = new String[errors.length]; for (int index = 0; index < errors.length; index++) stringErrors[index] = errors[index].toString(); assertErrorsOccurred(stringErrors); } protected void assertErrorsOccurred(String... errors) { Assert.assertEquals("mismatching numbers of errors", errors.length, this.errors.size()); for (int index = 0; index < errors.length; index++) Assert.assertEquals("mismatching #" + index + " errors", errors[index], this.errors.get(index)); } protected void assertNoErrorsOccurred() { Assert.assertEquals("Expected no errors", 0, errors.size()); } protected void assertSessionStatusFlow(SessionStatus... statuses) { if (statuses.length != sessionStatusFlow.size()) Assert.fail("Mismatching numbers of status transitions: expected " + Arrays.toString(statuses) + " actual " + sessionStatusFlow.toString() + ""); for (int index = 0; index < statuses.length; index++) Assert.assertEquals("mismatching #" + index + " statuses", statuses[index], sessionStatusFlow.get(index)); } protected void assertNextTargetSeqNum(int expected) { Assert.assertEquals("mismatching target seq nums", expected, sessionState.getNextTargetSeqNum()); } protected void assertNextSenderSeqNum(int expected) { Assert.assertEquals("mismatching sender seq nums", expected, sessionState.getNextSenderSeqNum()); } protected void assertNextSeqNums(int target, int sender) { assertNextTargetSeqNum(target); assertNextSenderSeqNum(sender); } protected String simulateProcessing(String... inboundMessages) { TextOutputChannel outputChannel = new TextOutputChannel() { @Override public void write(byte[] buffer, int offset, int length) throws IOException { if (sb.length() > 0) sb.append('\n'); super.write(buffer, offset, length); } @Override public void close() throws IOException { // do not clear } }; for (int i = 0; i < inboundMessages.length; i++) { String inboundMessage = inboundMessages[i]; int messageLength = findMessageLength(inboundMessage.replace('|', (char) 0x01)); Assert.assertEquals("BodyLen(9) specified in the message #" + i + " matches string size", messageLength, inboundMessage.length()); } communicator.connect(new PredefinedInputChannel(inboundMessages), outputChannel); communicator.processInboundMessages(); return outputChannel.toString(); } protected void fillMessageStore(int startMsgSeqNum, String... messages) { for (String message : messages) messageStore.put(startMsgSeqNum++, AsciiUtils.getBytes(message.replace('|', '\u0001')), 0, message.length()); } protected static void assertMessages(String actualMessages, String... expectedMessages) { Assert.assertEquals("Messages are not equal", toString(expectedMessages), actualMessages); } private static String toString(String... messages) { StringBuilder builder = new StringBuilder(1024); for (String message : messages) { if (builder.length() > 0) builder.append('\n'); builder.append(message); } return builder.toString(); } private static int findMessageLength(String message) { DefaultMessageParser parser = new DefaultMessageParser(); parser.set(AsciiUtils.getBytes(message), 0, message.length()); //Assuming ASCII while (parser.next()) { final int tagNum = parser.getTagNum(); if (tagNum == FixTags.BodyLength) { return parser.getIntValue() + parser.getOffset() + FixCommunicator.CHECKSUM_LENGTH; } } throw new IllegalArgumentException("Can't find BodyLength(9)"); } }