From 3b9c89747aa5acc05c083611eca7445c8d6fd93e Mon Sep 17 00:00:00 2001 From: aymen Date: Tue, 8 Sep 2026 18:17:29 +0200 Subject: [PATCH 1/2] Fix logonSent state when MessageStore fails to persist Logon (#1302) --- .../src/main/java/quickfix/Session.java | 8 +-- .../src/test/java/quickfix/SessionTest.java | 59 +++++++++++++++++-- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/quickfixj-core/src/main/java/quickfix/Session.java b/quickfixj-core/src/main/java/quickfix/Session.java index 87e6451f9..514de05c7 100644 --- a/quickfixj-core/src/main/java/quickfix/Session.java +++ b/quickfixj-core/src/main/java/quickfix/Session.java @@ -2107,7 +2107,6 @@ private boolean generateLogon() throws IOException { } state.setLastReceivedTime(SystemTime.currentTimeMillis()); state.clearTestRequestCounter(); - state.setLogonSent(true); logonAttempts++; if (enableNextExpectedMsgSeqNum) { @@ -2117,7 +2116,9 @@ private boolean generateLogon() throws IOException { } setLogonTags(logon); - return sendRaw(logon, 0); + final boolean result = sendRaw(logon, 0); + state.setLogonSent(result); + return result; } /** @@ -2650,8 +2651,7 @@ private void generateLogon(Message otherLogon, int expectedTargetNum) throws Fie } setLogonTags(logon); - sendRaw(logon, 0); - state.setLogonSent(true); + state.setLogonSent(sendRaw(logon, 0)); } private void persist(Header header, String messageString, int num) throws IOException, FieldNotFound { diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 88368fa45..34ae9a5ee 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -19,6 +19,7 @@ import quickfix.field.OrigSendingTime; import quickfix.field.PossDupFlag; import quickfix.field.RefSeqNum; +import quickfix.field.ResetSeqNumFlag; import quickfix.field.SenderCompID; import quickfix.field.SendingTime; import quickfix.field.SessionStatus; @@ -27,7 +28,6 @@ import quickfix.field.Text; import quickfix.field.converter.UtcTimeOnlyConverter; import quickfix.field.converter.UtcTimestampConverter; -import quickfix.field.ResetSeqNumFlag; import quickfix.fix44.Heartbeat; import quickfix.fix44.Logon; import quickfix.fix44.Logout; @@ -52,7 +52,6 @@ import java.time.ZoneOffset; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Collection; import java.util.Date; import java.util.List; import java.util.TimeZone; @@ -66,16 +65,16 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import org.mockito.Mockito; import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; - import static quickfix.SessionFactoryTestSupport.createSession; /** @@ -1824,6 +1823,58 @@ public void testNonLogonMessageFIXT() throws Exception { } } + /** + * QFJ-1302: The Session's logonSent state should only be set to true + * if the Logon message was actually sent, i.e. if the underlying + * MessageStore successfully persisted it. Previously, logonSent was + * set unconditionally before checking the result of sendRaw(). + */ + @Test + // QFJ-1302 + public void testLogonNotMarkedAsSentWhenMessageStorePersistFails() throws Exception { + final Application application = new UnitTestApplication(); + final SessionID sessionID = new SessionID( + FixVersions.BEGINSTRING_FIX44, "SENDER", "TARGET"); + + final MessageStoreFactory mockMessageStoreFactory = mock(MessageStoreFactory.class); + final MessageStore mockMessageStore = mock(MessageStore.class); + when(mockMessageStoreFactory.create(sessionID)).thenReturn(mockMessageStore); + when(mockMessageStore.getNextSenderMsgSeqNum()).thenReturn(1); + when(mockMessageStore.getNextTargetMsgSeqNum()).thenReturn(1); + when(mockMessageStore.getCreationTime()).thenReturn(new Date()); + + // Simulate the persistence failure described in ticket QFJ-1302 + doThrow(new IOException("Simulated persist failure")) + .when(mockMessageStore).set(anyInt(), anyString()); + + final MessageQueueFactory mockMessageQueueFactory = mock(MessageQueueFactory.class); + final MessageQueue mockMessageQueue = mock(MessageQueue.class); + when(mockMessageQueueFactory.create(sessionID)).thenReturn(mockMessageQueue); + + final LogFactory mockLogFactory = mock(LogFactory.class); + final Log mockLog = mock(Log.class); + when(mockLogFactory.create(sessionID)).thenReturn(mockLog); + + try (Session session = new Session(application, + mockMessageStoreFactory, mockMessageQueueFactory, sessionID, null, null, null, mockLogFactory, + new DefaultMessageFactory(), 30, false, 30, UtcTimestampPrecision.MILLIS, true, false, + false, false, false, false, true, false, 1.5, null, true, + new int[] { 5 }, false, false, false, false, true, false, true, false, + null, true, 0, false, false, true, new ArrayList<>(), Session.DEFAULT_HEARTBEAT_TIMEOUT_MULTIPLIER, false)) { + + final UnitTestResponder responder = new UnitTestResponder(); + session.setResponder(responder); + + session.logon(); + session.next(); + + final SessionState state = getSessionState(session); + assertFalse( + "logonSent should remain false when the MessageStore fails to persist the Logon", + state.isLogonSent()); + } + } + private void processMessage(Session session, Message message) throws FieldNotFound, RejectLogon, IncorrectDataFormat, IncorrectTagValue, UnsupportedMessageType, IOException, From 9fbc1dc0aaeed8541695097e39f07f6e62553c86 Mon Sep 17 00:00:00 2001 From: aymen Date: Tue, 8 Sep 2026 18:24:22 +0200 Subject: [PATCH 2/2] Fix logonSent state when MessageStore fails to persist Logon (#1302) --- quickfixj-core/src/test/java/quickfix/SessionTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickfixj-core/src/test/java/quickfix/SessionTest.java b/quickfixj-core/src/test/java/quickfix/SessionTest.java index 34ae9a5ee..490f2ae45 100644 --- a/quickfixj-core/src/test/java/quickfix/SessionTest.java +++ b/quickfixj-core/src/test/java/quickfix/SessionTest.java @@ -19,7 +19,6 @@ import quickfix.field.OrigSendingTime; import quickfix.field.PossDupFlag; import quickfix.field.RefSeqNum; -import quickfix.field.ResetSeqNumFlag; import quickfix.field.SenderCompID; import quickfix.field.SendingTime; import quickfix.field.SessionStatus; @@ -28,6 +27,7 @@ import quickfix.field.Text; import quickfix.field.converter.UtcTimeOnlyConverter; import quickfix.field.converter.UtcTimestampConverter; +import quickfix.field.ResetSeqNumFlag; import quickfix.fix44.Heartbeat; import quickfix.fix44.Logon; import quickfix.fix44.Logout; @@ -75,6 +75,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; + import static quickfix.SessionFactoryTestSupport.createSession; /**