test: regression tests for newBegin bug in Session.resendMessages (issue #344)#1194
test: regression tests for newBegin bug in Session.resendMessages (issue #344)#1194Copilot wants to merge 4 commits into
Conversation
…endMessages) Agent-Logs-Url: https://github.com/quickfix-j/quickfixj/sessions/e4d5edec-ed31-4a6c-9226-39ed746f0f49 Co-authored-by: chrjohn <6644028+chrjohn@users.noreply.github.com>
|
@copilot please add another unit test that basically does the same as your newly added test, but make the session use "enableNextExpectedMsgSeqNum=true". |
Done. The existing test has been refactored to delegate to a shared private helper ( Both tests intentionally fail on the current code, but for different reasons:
|
In
Session.resendMessages, when the last retrieved persisted message is an admin message,appMessageJustSentisfalseat loop end, sonewBeginis never updated frombeginSeqNo. The subsequentgenerateSequenceResetIfNeededcall emits a SequenceReset-GapFill with aMsgSeqNumthat is too low — overlapping application messages already resent to the counterparty.Change
Adds two failing regression tests to
SessionTest(sharing a common private helper) that isolate the scenario with and withoutenableNextExpectedMsgSeqNum:Scenario (
enableNextExpectedMsgSeqNum=false):NextSenderMsgSeqNum = 11When the counterparty sends
ResendRequest(BeginSeqNo=1), the expected final SequenceReset is:Current code produces:
The test asserts
MsgSeqNum=6and intentionally fails on the current code (expected:<[6]> but was:<[1]>).Scenario (
enableNextExpectedMsgSeqNum=true):With this mode, the session does not send an explicit ResendRequest at logon time (the resend is implicit via tag 789), so app messages occupy seqnos 2–4 instead of 3–4. The bug manifests differently: the post-loop branch in
resendMessagesskipsgenerateSequenceResetIfNeededentirely, omitting the trailing gap-fill SequenceReset. The test expects 7 outgoing messages (the last beingSequenceReset(MsgSeqNum=6, NewSeqNo=11)) and intentionally fails on the current code with only 6 messages sent.The root cause —
newBeginshould be updated inside the loop each time an app message is successfully resent, not only after the loop based on the last message type — is left for a separate fix PR.Original prompt
Create a PR against
masterin repositoryquickfix-j/quickfixjthat adds a unit test which reproduces issue #344 (bug inSession.resendMessages/generateSequenceResetIfNeededinvolvingnewBegin).Requirements:
beginSeqNo=2,endSeqNo=10(or similar) where the message store returns only a subset (e.g., 2..6) and within those:appMessageJustSentto be false at loop end andnewBeginto remainbeginSeqNo.generateSequenceResetIfNeededuses an incorrect begin sequence number (too low, e.g. begins at 2 instead of 6). The test should fail on current behavior to highlight the bug.sendRaw/ outgoing queue) rather than calling private methods directly.SessionState/store).quickfixj-core) using the existing test framework already used in the repo.Context:
quickfixj-core/src/main/java/quickfix/Session.javaaround the computation ofnewBeginafter the resend loop and call togenerateSequenceResetIfNeeded.resendMessages(...)andgenerateSequenceResetIfNeeded(...).SequenceResetmight use wrongMsgSeqNum, message will be ignored by counterparty #344Deliverables:
The following is the prior conversation context from the user's chat exploration (may be truncated):
User: Could you please help me understand this issue? Check the position of the possible bug in the screenshot
Assistant: Now I have a clear picture of the full
resendMessagesmethod. Let me put it all together to explain the bug.Understanding the Bug in
resendMessages/generateSequenceResetIfNeededHere's the relevant section of the code at the end of
resendMessages, which is where the bug lives:The Bug — Step by Step
Consider resending messages 2 to 10, but persistence only has messages 2 to 6:
appMessageJustSent = true,begin = 0appMessageJustSent = true,begin = 0appMessageJustSent = true,begin = 0appMessageJustSent = true,begin = 0begin = 6,appMessageJustSent = falseAfter the loop:
appMessageJustSent = false(because the last message processed was an admin message at seqno 6)msgSeqNum = 6(last message in persistence)begin = 6(set when admin message was encountered)Because
appMessageJustSentisfalse,newBeginstays at its initial value:beginSeqNo= 2.Then
generateSequenceResetIfNeededis called withbeginSeqNo = 2, sending a SequenceReset (gap-fill) FROM 2 TO 11.But the counterparty already processed app messages 2–5, and is now expecting seqno 6. A SequenceReset from seqno 2 will be rejected as "sequence number too low"!
The Root Cause
The
newBeginvariable is only updated after the loop based on whether the very last message was an app message. It doesn't track the "beginning of the trailing gap" correctly when the sequence ends with one or more admin messages after the last app message.###...
This pull request was created from Copilot chat.