@@ -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