Skip to content

Commit

Permalink
Merge branch 'martinadams-issue_#278'
Browse files Browse the repository at this point in the history
  • Loading branch information
mgatny committed Jul 8, 2015
2 parents 4919476 + f49499f commit bc135b1
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 10 deletions.
1 change: 1 addition & 0 deletions NEXT_VERSION.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ Changes since the last version (oldest first):
* (patch) #315 - make config file section headers be case-insensitive, for parity with QF/j (gbirchmeier)
* (minor) #314 - New feature: add/remove sessions dynamically (martinadams)
* (patch) #273 - prevent non-logon message traffic unless fully logged on (martinadams)
* (patch) #278 - fix for mis-sequenced gap fills in re-requested messages (martinadams)
20 changes: 10 additions & 10 deletions QuickFIXn/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -795,20 +795,20 @@ protected void NextResendRequest(Message resendReq)
current = msgSeqNum + 1;
}

if (begin != 0)
int nextSeqNum = state_.GetNextSenderMsgSeqNum();
if (++endSeqNo > nextSeqNum)
{
GenerateSequenceReset(resendReq, begin, msgSeqNum + 1);
endSeqNo = nextSeqNum;
}

if (endSeqNo > msgSeqNum)
if (begin == 0)
{
endSeqNo = endSeqNo + 1;
int next = state_.GetNextSenderMsgSeqNum();
if (endSeqNo > next)
{
endSeqNo = next;
}
GenerateSequenceReset(resendReq, begSeqNo, endSeqNo);
begin = current;
}

if (endSeqNo > begin)
{
GenerateSequenceReset(resendReq, begin, endSeqNo);
}
}
msgSeqNum = resendReq.Header.GetInt(Tags.MsgSeqNum);
Expand Down
64 changes: 64 additions & 0 deletions UnitTests/SessionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ public void DumpMsgLookup()
}
}

public int GetCount(string msgType)
{
return msgLookup.ContainsKey(msgType) ? msgLookup[msgType].Count : 0;
}

#endregion
}

Expand Down Expand Up @@ -432,6 +437,65 @@ public void NextResendRequestNoMessagePersist()
Assert.IsFalse(RESENT());
}

[Test]
public void TestGapFillOnResend()
{
// Engineer a gap fill at the beginning of a re-send range, in the middle, and at the end
Logon(); //seq 1
QuickFix.FIX42.NewOrderSingle order = new QuickFix.FIX42.NewOrderSingle(
new QuickFix.Fields.ClOrdID("1"),
new QuickFix.Fields.HandlInst(QuickFix.Fields.HandlInst.MANUAL_ORDER),
new QuickFix.Fields.Symbol("IBM"),
new QuickFix.Fields.Side(QuickFix.Fields.Side.BUY),
new QuickFix.Fields.TransactTime(),
new QuickFix.Fields.OrdType(QuickFix.Fields.OrdType.LIMIT));

order.Header.SetField(new QuickFix.Fields.TargetCompID(sessionID.TargetCompID));
order.Header.SetField(new QuickFix.Fields.SenderCompID(sessionID.SenderCompID));

int[] gapStarts = new[] { 1, 5, 11 }; // 1st gap from seq num 1 to 2 is just the Logon message
int[] gapEnds = new[] { 2, 8, 15 };
int orderCount = 0;

for (int msgSeqNum = gapEnds[0]; msgSeqNum < gapStarts[1]; ++msgSeqNum)
{
order.Header.SetField(new QuickFix.Fields.MsgSeqNum(msgSeqNum));
session.Send(order);
++orderCount;
} //seq 4, next is 5

for (int msgSeqNum = gapStarts[1]; msgSeqNum < gapEnds[1]; ++msgSeqNum)
{
session.GenerateHeartbeat();
} //seq 7, next is 8

for (int msgSeqNum = gapEnds[1]; msgSeqNum < gapStarts[2]; ++msgSeqNum)
{
order.Header.SetField(new QuickFix.Fields.MsgSeqNum(msgSeqNum));
session.Send(order);
++orderCount;
} //seq 10, next is 11

for (int msgSeqNum = gapStarts[2]; msgSeqNum < gapEnds[2]; ++msgSeqNum)
{
session.GenerateHeartbeat();
} // seq 11 - 14

responder.msgLookup.Clear();
SendResendRequest(1, 100);

Assert.AreEqual(responder.GetCount(QuickFix.Fields.MsgType.NEWORDERSINGLE), orderCount);
Assert.AreEqual(responder.GetCount(QuickFix.Fields.MsgType.SEQUENCE_RESET), gapStarts.Length);

int count = -1;
foreach (QuickFix.Message sequenceResestMsg in responder.msgLookup[QuickFix.Fields.MsgType.SEQUENCE_RESET])
{
Assert.AreEqual(sequenceResestMsg.GetField(QuickFix.Fields.Tags.GapFillFlag), "Y");
Assert.AreEqual(sequenceResestMsg.Header.GetInt(QuickFix.Fields.Tags.MsgSeqNum), gapStarts[++count]);
Assert.AreEqual(sequenceResestMsg.GetInt(QuickFix.Fields.Tags.NewSeqNo), gapEnds[count]);
}
}

public void AssertMsInTag(string msgType, int tag, bool shouldHaveMs)
{
QuickFix.Message msg = responder.msgLookup[msgType].Last();
Expand Down

0 comments on commit bc135b1

Please sign in to comment.