Skip to content

Commit 4fa8a0a

Browse files
committed
Merge branch 'flakronv-gapFillBug'
2 parents 7802602 + 11579a7 commit 4fa8a0a

File tree

2 files changed

+109
-3
lines changed

2 files changed

+109
-3
lines changed

quickfixj-core/src/main/java/quickfix/Session.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,8 +2157,10 @@ private void resendMessages(Message receivedMessage, int beginSeqNo, int endSeqN
21572157
int msgSeqNum = 0;
21582158
int begin = 0;
21592159
int current = beginSeqNo;
2160+
boolean appMessageJustSent = false;
21602161

21612162
for (final String message : messages) {
2163+
appMessageJustSent = false;
21622164
final Message msg;
21632165
try {
21642166
// QFJ-626
@@ -2191,6 +2193,7 @@ private void resendMessages(Message receivedMessage, int beginSeqNo, int endSeqN
21912193
getLog().onEvent("Resending Message: " + msgSeqNum);
21922194
send(msg.toString());
21932195
begin = 0;
2196+
appMessageJustSent = true;
21942197
} else {
21952198
if (begin == 0) {
21962199
begin = msgSeqNum;
@@ -2199,21 +2202,27 @@ private void resendMessages(Message receivedMessage, int beginSeqNo, int endSeqN
21992202
}
22002203
current = msgSeqNum + 1;
22012204
}
2205+
2206+
int newBegin = beginSeqNo;
2207+
if (appMessageJustSent) {
2208+
newBegin = msgSeqNum + 1;
2209+
}
22022210
if (enableNextExpectedMsgSeqNum) {
22032211
if (begin != 0) {
22042212
generateSequenceReset(receivedMessage, begin, msgSeqNum + 1);
2205-
} else
2213+
} else {
22062214
/*
22072215
* I've added an else here as I managed to fail this without it in a unit test, however the unit test data
22082216
* may not have been realistic to production on the other hand.
22092217
* Apart from the else
22102218
*/
2211-
generateSequenceResetIfNeeded(receivedMessage, beginSeqNo, endSeqNo, msgSeqNum);
2219+
generateSequenceResetIfNeeded(receivedMessage, newBegin, endSeqNo, msgSeqNum);
2220+
}
22122221
} else {
22132222
if (begin != 0) {
22142223
generateSequenceReset(receivedMessage, begin, msgSeqNum + 1);
22152224
}
2216-
generateSequenceResetIfNeeded(receivedMessage, beginSeqNo, endSeqNo, msgSeqNum);
2225+
generateSequenceResetIfNeeded(receivedMessage, newBegin, endSeqNo, msgSeqNum);
22172226
}
22182227
}
22192228

quickfixj-core/src/test/java/quickfix/SessionTest.java

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
import static org.mockito.Mockito.atLeastOnce;
1111
import static org.mockito.Mockito.mock;
1212
import static org.mockito.Mockito.stub;
13+
import static org.mockito.Mockito.times;
1314
import static org.mockito.Mockito.verify;
1415
import static org.mockito.Mockito.verifyNoMoreInteractions;
16+
import static org.mockito.Mockito.when;
1517
import static quickfix.SessionFactoryTestSupport.createSession;
1618

1719
import java.io.BufferedOutputStream;
@@ -28,6 +30,7 @@
2830

2931
import org.junit.Before;
3032
import org.junit.Test;
33+
import org.mockito.ArgumentCaptor;
3134

3235
import quickfix.field.ApplVerID;
3336
import quickfix.field.BeginSeqNo;
@@ -1862,6 +1865,100 @@ private void testSequenceResetGapFillWithChunkSize(int chunkSize)
18621865
session.close();
18631866
}
18641867

1868+
@Test
1869+
public void correct_sequence_number_for_last_gap_fill_if_next_sender_sequence_number_is_higher_than_the_last_message_resent()
1870+
throws IOException, InvalidMessage, FieldNotFound, RejectLogon, UnsupportedMessageType,
1871+
IncorrectTagValue, IncorrectDataFormat, NoSuchFieldException, IllegalAccessException {
1872+
final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET");
1873+
final boolean resetOnLogon = false;
1874+
final boolean validateSequenceNumbers = true;
1875+
1876+
Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(),
1877+
sessionID, null, null, null,
1878+
new DefaultMessageFactory(), 30, false, 30, true, resetOnLogon,
1879+
false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers,
1880+
new int[]{5}, false, false, false, true, false, true, false, null, true, 0,
1881+
false, false);
1882+
1883+
Responder mockResponder = mock(Responder.class);
1884+
when(mockResponder.send(anyString())).thenReturn(true);
1885+
session.setResponder(mockResponder);
1886+
1887+
session.logon();
1888+
session.next();
1889+
1890+
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
1891+
verify(mockResponder).send(messageCaptor.capture());
1892+
session.next(createLogonResponse(sessionID, new Message(messageCaptor.getValue()), 101));
1893+
MessageStore messageStore = session.getStore();
1894+
1895+
for (int i=messageStore.getNextSenderMsgSeqNum(); i<=5; i++) {
1896+
String executionReportString = "8=FIX.4.2\0019=0246\00135=8\001115=THEM\00134=" + i + "\00143=Y\001122=20100908-17:52:37.920\00149=THEM\00156=US\001369=178\00152=20100908-17:59:30.642\00137=10118506\00111=a00000052.1\00117=17537743\00120=0\001150=4\00139=4\00155=ETFC\00154=1\00138=500000\00144=0.998\00132=0\00131=0\001151=0\00114=0\0016=0\00160=20100908-17:52:37.920\00110=80\001";
1897+
messageStore.set(i, executionReportString);
1898+
messageStore.incrNextSenderMsgSeqNum();
1899+
}
1900+
1901+
//simulate a bunch of admin messages that were not persisted
1902+
for (int i=0; i<5; i++)
1903+
messageStore.incrNextSenderMsgSeqNum();
1904+
1905+
final Message resendRequest = createResendRequest(1, 1);
1906+
session.next(resendRequest);
1907+
1908+
verify(mockResponder, times(7)).send(messageCaptor.capture());
1909+
Message lastGapFill = new Message(messageCaptor.getAllValues().get(messageCaptor.getAllValues().size()-1));
1910+
assertEquals("4", lastGapFill.getHeader().getString(MsgType.FIELD));
1911+
assertEquals(lastGapFill.getHeader().getString(MsgSeqNum.FIELD), "6");
1912+
}
1913+
1914+
@Test
1915+
public void correct_sequence_number_for_last_gap_fill_if_next_sender_sequence_number_is_higher_than_last_message_resent_when_enableNextExpectedMsgSeqNum_is_true()
1916+
throws FieldNotFound, InvalidMessage, IOException, RejectLogon, IncorrectDataFormat, IncorrectTagValue,
1917+
UnsupportedMessageType {
1918+
boolean enableNextExpectedMsgSeqNum = true;
1919+
1920+
final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET");
1921+
final boolean resetOnLogon = false;
1922+
final boolean validateSequenceNumbers = true;
1923+
1924+
Session session = new Session(new UnitTestApplication(), new MemoryStoreFactory(),
1925+
sessionID, null, null, null,
1926+
new DefaultMessageFactory(), 30, false, 30, true, resetOnLogon,
1927+
false, false, false, false, false, true, false, 1.5, null, validateSequenceNumbers,
1928+
new int[]{5}, false, false, false, true, false, true, false, null, true, 0,
1929+
enableNextExpectedMsgSeqNum, false);
1930+
1931+
Responder mockResponder = mock(Responder.class);
1932+
when(mockResponder.send(anyString())).thenReturn(true);
1933+
session.setResponder(mockResponder);
1934+
1935+
session.logon();
1936+
session.next();
1937+
1938+
ArgumentCaptor<String> messageCaptor = ArgumentCaptor.forClass(String.class);
1939+
verify(mockResponder).send(messageCaptor.capture());
1940+
session.next(createLogonResponse(sessionID, new Message(messageCaptor.getValue()), 101));
1941+
MessageStore messageStore = session.getStore();
1942+
1943+
for (int i=messageStore.getNextSenderMsgSeqNum(); i<=5; i++) {
1944+
String executionReportString = "8=FIX.4.2\0019=0246\00135=8\001115=THEM\00134=" + i + "\00143=Y\001122=20100908-17:52:37.920\00149=THEM\00156=US\001369=178\00152=20100908-17:59:30.642\00137=10118506\00111=a00000052.1\00117=17537743\00120=0\001150=4\00139=4\00155=ETFC\00154=1\00138=500000\00144=0.998\00132=0\00131=0\001151=0\00114=0\0016=0\00160=20100908-17:52:37.920\00110=80\001";
1945+
messageStore.set(i, executionReportString);
1946+
messageStore.incrNextSenderMsgSeqNum();
1947+
}
1948+
1949+
//simulate a bunch of admin messages that were not persisted
1950+
for (int i=0; i<5; i++)
1951+
messageStore.incrNextSenderMsgSeqNum();
1952+
1953+
final Message resendRequest = createResendRequest(1, 1);
1954+
session.next(resendRequest);
1955+
1956+
verify(mockResponder, times(7)).send(messageCaptor.capture());
1957+
Message lastGapFill = new Message(messageCaptor.getAllValues().get(messageCaptor.getAllValues().size()-1));
1958+
assertEquals("4", lastGapFill.getHeader().getString(MsgType.FIELD));
1959+
assertEquals(lastGapFill.getHeader().getString(MsgSeqNum.FIELD), "6");
1960+
}
1961+
18651962
@Test
18661963
// QFJ-795
18671964
public void testMsgSeqNumTooHighWithDisconnectOnError() throws Exception {

0 commit comments

Comments
 (0)