Skip to content

Commit 88c2ee3

Browse files
Copilotchrjohn
andcommitted
Add test demonstrating Reject messages not resent in current code
Co-authored-by: chrjohn <6644028+chrjohn@users.noreply.github.com>
1 parent dae7fc9 commit 88c2ee3

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

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

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,110 @@ public void testResendMessagesWithIncorrectChecksum() throws Exception {
13981398
}
13991399
}
14001400

1401+
// Test for issue #597 - demonstrates current behavior where Reject messages are NOT resent
1402+
// This test documents the bug before PR #1124's fix
1403+
@Test
1404+
public void testRejectMessagesNotResentInCurrentCode() throws Exception {
1405+
final UnitTestApplication application = new UnitTestApplication();
1406+
final SessionID sessionID = new SessionID(FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET");
1407+
1408+
// Create session with default settings (ForceResendWhenCorruptedStore=false)
1409+
try (Session session = SessionFactoryTestSupport.createSession(sessionID, application, false, false, true, true, null)) {
1410+
// Use a responder that captures all sent messages
1411+
FailingResponder responder = new FailingResponder(100); // Allow many successful sends
1412+
session.setResponder(responder);
1413+
final SessionState state = getSessionState(session);
1414+
1415+
// Logon
1416+
final Logon logonToSend = new Logon();
1417+
setUpHeader(session.getSessionID(), logonToSend, true, 1);
1418+
logonToSend.setInt(HeartBtInt.FIELD, 30);
1419+
logonToSend.setInt(EncryptMethod.FIELD, EncryptMethod.NONE_OTHER);
1420+
logonToSend.toString(); // calculate length/checksum
1421+
session.next(logonToSend);
1422+
1423+
// Send messages that will be stored:
1424+
// seq 2: application message
1425+
session.send(createAppMessage(2));
1426+
// seq 3: Reject message (session-level but should be resent per FIX spec)
1427+
Message rejectMsg = createReject(3, 1);
1428+
session.send(rejectMsg);
1429+
// seq 4: application message
1430+
session.send(createAppMessage(4));
1431+
// seq 5: Heartbeat message (session-level, should NOT be resent)
1432+
Message heartbeatMsg = createHeartbeatMessage(5);
1433+
session.send(heartbeatMsg);
1434+
1435+
// Clear the sent messages from initial send
1436+
int initialMessageCount = responder.sentMessages.size();
1437+
responder.sentMessages.clear();
1438+
responder.sendCallCount = 0;
1439+
1440+
// Request resend of messages 1-5
1441+
Message resendRequest = createResendRequest(100, 1);
1442+
resendRequest.toString(); // calculate length/checksum
1443+
processMessage(session, resendRequest);
1444+
1445+
// Verify messages sent during resend
1446+
List<Message> resentMessages = new ArrayList<>();
1447+
for (String msgData : responder.sentMessages) {
1448+
resentMessages.add(new Message(msgData));
1449+
}
1450+
1451+
// Current behavior verification:
1452+
// 1. Should have sent: SequenceReset(1-2), AppMsg(2), SequenceReset(3-4), AppMsg(4), SequenceReset(5-6)
1453+
// The Reject message should be included in a gap fill (bug)
1454+
1455+
boolean foundSeqReset1 = false; // Gap fill for Logon (seq 1)
1456+
boolean foundAppMsg2 = false;
1457+
boolean foundSeqReset3 = false; // Gap fill that includes Reject (seq 3) - this is the bug
1458+
boolean foundAppMsg4 = false;
1459+
boolean foundSeqReset5 = false; // Gap fill for Heartbeat (seq 5)
1460+
boolean foundRejectResend = false;
1461+
1462+
for (Message msg : resentMessages) {
1463+
String msgType = msg.getHeader().getString(MsgType.FIELD);
1464+
int msgSeqNum = msg.getHeader().getInt(MsgSeqNum.FIELD);
1465+
1466+
if (msgType.equals(SequenceReset.MSGTYPE)) {
1467+
boolean isGapFill = msg.isSetField(GapFillFlag.FIELD) && msg.getBoolean(GapFillFlag.FIELD);
1468+
int newSeqNo = msg.getInt(NewSeqNo.FIELD);
1469+
1470+
if (isGapFill && msgSeqNum == 1 && newSeqNo == 2) {
1471+
foundSeqReset1 = true; // Gap fill over Logon
1472+
} else if (isGapFill && msgSeqNum == 3 && newSeqNo == 4) {
1473+
foundSeqReset3 = true; // Gap fill over Reject (bug - should not gap fill)
1474+
} else if (isGapFill && msgSeqNum == 5 && newSeqNo == 6) {
1475+
foundSeqReset5 = true; // Gap fill over Heartbeat
1476+
}
1477+
} else if (msgType.equals(News.MSGTYPE)) {
1478+
// Application message
1479+
boolean isPossDup = msg.getHeader().isSetField(PossDupFlag.FIELD)
1480+
&& msg.getHeader().getBoolean(PossDupFlag.FIELD);
1481+
assertTrue("Application message should have PossDupFlag set", isPossDup);
1482+
1483+
if (msgSeqNum == 2) {
1484+
foundAppMsg2 = true;
1485+
} else if (msgSeqNum == 4) {
1486+
foundAppMsg4 = true;
1487+
}
1488+
} else if (msgType.equals(Reject.MSGTYPE)) {
1489+
foundRejectResend = true;
1490+
}
1491+
}
1492+
1493+
// Verify current behavior (documents the bug)
1494+
assertTrue("Should send gap fill for Logon (seq 1)", foundSeqReset1);
1495+
assertTrue("Should resend application message (seq 2)", foundAppMsg2);
1496+
assertTrue("Should send gap fill for Reject (seq 3) - this is the bug", foundSeqReset3);
1497+
assertTrue("Should resend application message (seq 4)", foundAppMsg4);
1498+
assertTrue("Should send gap fill for Heartbeat (seq 5)", foundSeqReset5);
1499+
assertFalse("Reject message should NOT be resent in current code (bug)", foundRejectResend);
1500+
1501+
assertFalse(state.isResendRequested());
1502+
}
1503+
}
1504+
14011505
// QFJ-493
14021506
@Test
14031507
public void testGapFillSatisfiesResendRequest() throws Exception {

0 commit comments

Comments
 (0)