From d05953ac1520d932e5424f1c1917d13bdf21d3f4 Mon Sep 17 00:00:00 2001 From: Mike Gatny Date: Tue, 2 Aug 2011 16:42:21 -0500 Subject: [PATCH] Use AT runner '-o' option to write TestResult.xml instead of using IO redirection. AT 11c passing (send Reject for invalid seq reset) --- AcceptanceTest/runat.bat | 4 +- .../Fields/Converters/IntConverter.cs | 9 +- QuickFIX.NET/FixValues.cs | 51 +++++++++-- QuickFIX.NET/Message/FieldMap.cs | 5 ++ QuickFIX.NET/Message/Message.cs | 85 ++++++++++++++++++ QuickFIX.NET/ResendRange.cs | 5 ++ QuickFIX.NET/Session.cs | 86 +++++++++++++++++-- QuickFIX.NET/SessionState.cs | 2 + QuickFIX.NET/SocketReader.cs | 29 ++++++- QuickFIX.NET/Values.cs | 2 - acceptance_test.bat | 2 +- 11 files changed, 256 insertions(+), 24 deletions(-) diff --git a/AcceptanceTest/runat.bat b/AcceptanceTest/runat.bat index 160e2da29..58159a635 100755 --- a/AcceptanceTest/runat.bat +++ b/AcceptanceTest/runat.bat @@ -24,8 +24,8 @@ goto start call setup.bat %2 -REM release\at\atrun -t run -s "%DIR%\AcceptanceTest.exe cfg\at.cfg" -d . -c "ruby Runner.rb 127.0.0.1 %2 definitions\server\fix40\*.def definitions\server\fix41\*.def definitions\server\fix42\*.def definitions\server\fix43\*.def definitions\server\fix44\*.def definitions\server\fix50\*.def definitions\server\fix50sp1\*.def definitions\server\fix50sp2\*.def" -i .\ -release\at\atrun -t run -s "%DIR%\AcceptanceTest.exe cfg\at.cfg" -d . -c "ruby Runner.rb 127.0.0.1 %2 %TESTS%" -i .\ +REM release\at\atrun -t run -s "%DIR%\AcceptanceTest.exe cfg\at.cfg" -d . -c "ruby Runner.rb 127.0.0.1 %2 definitions\server\fix40\*.def definitions\server\fix41\*.def definitions\server\fix42\*.def definitions\server\fix43\*.def definitions\server\fix44\*.def definitions\server\fix50\*.def definitions\server\fix50sp1\*.def definitions\server\fix50sp2\*.def" -i .\ -o TestResult.xml +release\at\atrun -t run -s "%DIR%\AcceptanceTest.exe cfg\at.cfg" -d . -c "ruby Runner.rb 127.0.0.1 %2 %TESTS%" -i .\ -o TestResult.xml goto quit :usage diff --git a/QuickFIX.NET/Fields/Converters/IntConverter.cs b/QuickFIX.NET/Fields/Converters/IntConverter.cs index 07f945cfc..cf4d49b54 100644 --- a/QuickFIX.NET/Fields/Converters/IntConverter.cs +++ b/QuickFIX.NET/Fields/Converters/IntConverter.cs @@ -10,10 +10,11 @@ namespace QuickFix.Fields.Converters /// public static class IntConverter { - /// - /// Converts string to int - /// - /// + /// + /// Converts string to int + /// + /// + /// public static int Convert(string i) { try diff --git a/QuickFIX.NET/FixValues.cs b/QuickFIX.NET/FixValues.cs index 577938e42..c3788f9a8 100755 --- a/QuickFIX.NET/FixValues.cs +++ b/QuickFIX.NET/FixValues.cs @@ -1,6 +1,39 @@  namespace QuickFix { + public class FixValue + { + private T value_; + private string description_; + + public T Value { get { return value_; } } + public string Description { get { return description_; } } + + public FixValue(T value, string description) + { + value_ = value; + description_ = description; + } + + public override bool Equals(object obj) + { + if ((null == obj) || (this.GetType() != obj.GetType())) + return false; + FixValue rhs = (FixValue)obj; + return this.Value.Equals(rhs.Value); + } + + public override int GetHashCode() + { + return value_.GetHashCode(); + } + + public override string ToString() + { + return description_; + } + } + /// /// TODO generate this class /// @@ -8,19 +41,21 @@ namespace FixValues { public class MsgType { - public const string HEARTBEAT = "0"; - public const string TEST_REQUEST = "1"; - public const string RESEND_REQUEST = "2"; - public const string REJECT = "3"; - public const string SEQUENCE_RESET = "4"; - public const string LOGOUT = "5"; - public const string LOGON = "A"; + public const string HEARTBEAT = "0"; + public const string TEST_REQUEST = "1"; + public const string RESEND_REQUEST = "2"; + public const string REJECT = "3"; + public const string SEQUENCE_RESET = "4"; + public const string LOGOUT = "5"; + public const string LOGON = "A"; public const string NEW_ORDER_SINGLE = "D"; } public class SessionRejectReason { - public const int VALUE_IS_INCORRECT = 5; + public static FixValue INVALID_TAG_NUMBER = new FixValue(0, "Invalid tag number"); + public static FixValue VALUE_IS_INCORRECT = new FixValue(5, "Value is incorrect (out of range) for this tag"); + public static FixValue INVALID_MSGTYPE = new FixValue(11, "Invalid MsgType"); } } } diff --git a/QuickFIX.NET/Message/FieldMap.cs b/QuickFIX.NET/Message/FieldMap.cs index b43a8fba4..9f55b3130 100644 --- a/QuickFIX.NET/Message/FieldMap.cs +++ b/QuickFIX.NET/Message/FieldMap.cs @@ -42,6 +42,11 @@ public int[] getFieldOrder() return _fieldOrder; } + public bool RemoveField(int field) + { + return _fields.Remove(field); + } + /// /// set field in the fieldmap /// will overwrite field if it exists diff --git a/QuickFIX.NET/Message/Message.cs b/QuickFIX.NET/Message/Message.cs index d3055665c..cbd755d35 100644 --- a/QuickFIX.NET/Message/Message.cs +++ b/QuickFIX.NET/Message/Message.cs @@ -212,6 +212,91 @@ public static string GetMsgType(string msg) #endregion + public void ReverseRoute(Header header) + { + // required routing tags + this.Header.RemoveField(Fields.Tags.BeginString); + this.Header.RemoveField(Fields.Tags.SenderCompID); + this.Header.RemoveField(Fields.Tags.TargetCompID); + + if (header.isSetField(Fields.Tags.BeginString)) + { + string beginString = header.GetField(Fields.Tags.BeginString); + if (beginString.Length > 0) + this.Header.setField(new BeginString(beginString)); + + this.Header.RemoveField(Fields.Tags.OnBehalfOfLocationID); + this.Header.RemoveField(Fields.Tags.DeliverToLocationID); + + if (beginString.CompareTo("FIX.4.1") >= 0) + { + if (header.isSetField(Fields.Tags.OnBehalfOfLocationID)) + { + string onBehalfOfLocationID = header.GetField(Fields.Tags.OnBehalfOfLocationID); + if (onBehalfOfLocationID.Length > 0) + this.Header.setField(new DeliverToLocationID(onBehalfOfLocationID)); + } + + if (header.isSetField(Fields.Tags.DeliverToLocationID)) + { + string deliverToLocationID = header.GetField(Fields.Tags.DeliverToLocationID); + if (deliverToLocationID.Length > 0) + this.Header.setField(new OnBehalfOfLocationID(deliverToLocationID)); + } + } + } + + if (header.isSetField(Fields.Tags.SenderCompID)) + { + SenderCompID senderCompID = new SenderCompID(); + header.getField(senderCompID); + if (senderCompID.Obj.Length > 0) + this.Header.setField(new TargetCompID(senderCompID.Obj)); + } + + if (header.isSetField(Fields.Tags.TargetCompID)) + { + TargetCompID targetCompID = new TargetCompID(); + header.getField(targetCompID); + if (targetCompID.Obj.Length > 0) + this.Header.setField(new SenderCompID(targetCompID.Obj)); + } + + // optional routing tags + this.Header.RemoveField(Fields.Tags.OnBehalfOfCompID); + this.Header.RemoveField(Fields.Tags.OnBehalfOfSubID); + this.Header.RemoveField(Fields.Tags.DeliverToCompID); + this.Header.RemoveField(Fields.Tags.DeliverToSubID); + + if(header.isSetField(Fields.Tags.OnBehalfOfCompID)) + { + string onBehalfOfCompID = header.GetField(Fields.Tags.OnBehalfOfCompID); + if(onBehalfOfCompID.Length > 0) + this.Header.setField(new DeliverToCompID(onBehalfOfCompID)); + } + + if(header.isSetField(Fields.Tags.OnBehalfOfSubID)) + { + string onBehalfOfSubID = header.GetField( Fields.Tags.OnBehalfOfSubID); + if(onBehalfOfSubID.Length > 0) + this.Header.setField(new DeliverToSubID(onBehalfOfSubID)); + } + + if(header.isSetField(Fields.Tags.DeliverToCompID)) + { + string deliverToCompID = header.GetField(Fields.Tags.DeliverToCompID); + if(deliverToCompID.Length > 0) + this.Header.setField(new OnBehalfOfCompID(deliverToCompID)); + } + + if(header.isSetField(Fields.Tags.DeliverToSubID)) + { + string deliverToSubID = header.GetField(Fields.Tags.DeliverToSubID); + if(deliverToSubID.Length > 0) + this.Header.setField(new OnBehalfOfSubID(deliverToSubID)); + } + } + public int CheckSum() { return ( diff --git a/QuickFIX.NET/ResendRange.cs b/QuickFIX.NET/ResendRange.cs index 2bf7b7364..5de83f07b 100755 --- a/QuickFIX.NET/ResendRange.cs +++ b/QuickFIX.NET/ResendRange.cs @@ -14,5 +14,10 @@ public ResendRange(int begin, int end) BeginSeqNo = begin; EndSeqNo = end; } + + public override string ToString() + { + return BeginSeqNo + ":" + EndSeqNo; + } } } diff --git a/QuickFIX.NET/Session.cs b/QuickFIX.NET/Session.cs index f195ad64e..f11875fc8 100644 --- a/QuickFIX.NET/Session.cs +++ b/QuickFIX.NET/Session.cs @@ -196,6 +196,7 @@ public void Disconnect(string reason) public void Next() { //System.Console.WriteLine(state_.ToString()); + //this.Log.OnEvent(state_.ToString()); if (!IsEnabled) { @@ -323,6 +324,7 @@ public void Next(Message message) protected void NextQueued() { System.Console.WriteLine("FIXME - Session.NextQueued not implemented!"); + this.Log.OnEvent("FIXME - Session.NextQueued not implemented!"); } protected void NextLogon(Message logon) @@ -696,14 +698,86 @@ public bool GenerateHeartbeat(Message testRequest) return SendRaw(heartbeat, 0); } - public bool GenerateReject(Message msg, int err) - { - return GenerateReject(msg, err, 0); + public bool GenerateReject(Message message, FixValue sessionRejectReason) + { + return GenerateReject(message, sessionRejectReason, 0); + } + public bool GenerateReject(Message message, FixValue sessionRejectReason, int field) + { + string beginString = this.SessionID.BeginString; + + Message reject = new Message(); + reject.Header.setField(new Fields.MsgType(FixValues.MsgType.REJECT)); + reject.ReverseRoute(message.Header); + InitializeHeader(reject); + + string msgType; + if(message.Header.isSetField(Fields.Tags.MsgType)) + msgType = message.Header.GetField(Fields.Tags.MsgType); + else + msgType = ""; + + int msgSeqNum = 0; + if(message.Header.isSetField(Fields.Tags.MsgSeqNum)) + { + try + { + msgSeqNum = Fields.Converters.IntConverter.Convert(message.Header.GetField(Fields.Tags.MsgSeqNum)); /// FIXME + reject.setField(new Fields.RefSeqNum(msgSeqNum)); + } + catch(System.Exception) + { } + } + + if(beginString.CompareTo("FIX.4.2") >= 0) + { + if(msgType.Length > 0) + reject.setField(new Fields.RefMsgType(msgType)); + if (("FIX.4.2".Equals(beginString) && sessionRejectReason.Value <= FixValues.SessionRejectReason.INVALID_MSGTYPE.Value) || ("FIX.4.2".CompareTo(beginString) > 0)) + { + reject.setField(new Fields.SessionRejectReason(sessionRejectReason.Value)); + } + } + if ( !FixValues.MsgType.LOGON.Equals(msgType) + && !FixValues.MsgType.SEQUENCE_RESET.Equals(msgType) + && (msgSeqNum == state_.GetNextTargetMsgSeqNum()) ) + { + state_.IncrNextTargetMsgSeqNum(); + } + + if((0 != field) || FixValues.SessionRejectReason.INVALID_TAG_NUMBER.Equals(sessionRejectReason)) + { + PopulateRejectReason(reject, msgType, field, sessionRejectReason.Description); + this.Log.OnEvent("Message " + msgSeqNum + " Rejected: " + sessionRejectReason.Value + ":" + field); + } + else + { + PopulateRejectReason(reject, sessionRejectReason.Description); + this.Log.OnEvent("Message " + msgSeqNum + " Rejected: " + sessionRejectReason.Value); + } + + if (!state_.ReceivedLogon) + throw new QuickFIXException("Tried to send a reject while not logged on"); + + return SendRaw(reject, 0); + } + + protected void PopulateRejectReason(Message reject, string msgType, int field, string text) + { + if (FixValues.MsgType.REJECT.Equals(msgType) && "FIX.4.2".CompareTo(this.SessionID.BeginString) >= 0) + { + reject.setField(new Fields.RefTagID(field)); + reject.setField(new Fields.Text(text)); + } + else + { + reject.setField(new Fields.Text(text + " (" + field + ")")); + } } - public bool GenerateReject(Message msg, int err, int field) + + protected void PopulateRejectReason(Message reject, string text) { - System.Console.WriteLine("FIXME - GenerateReject not implemented!"); - return false; + reject.setField(new Fields.Text(text)); } /// diff --git a/QuickFIX.NET/SessionState.cs b/QuickFIX.NET/SessionState.cs index 722292e36..d1475a341 100755 --- a/QuickFIX.NET/SessionState.cs +++ b/QuickFIX.NET/SessionState.cs @@ -256,6 +256,7 @@ public bool ResendRequested() public void Queue(int msgSeqNum, Message msg) { System.Console.WriteLine("FIXME - SessionState.Queue(int,Message) not implemented!"); + this.Log.OnEvent("FIXME - SessionState.Queue(int,Message) not implemented!"); } public void ClearQueue() @@ -278,6 +279,7 @@ public override string ToString() .Append(", WithinHeartbeat=").Append(WithinHeartbeat()) .Append(", NeedHeartbeat=").Append(NeedHeartbeat()) .Append(", NeedTestRequest=").Append(NeedTestRequest()) + .Append(", ResendRange=").Append(GetResendRange()) .Append(" ]").ToString(); } diff --git a/QuickFIX.NET/SocketReader.cs b/QuickFIX.NET/SocketReader.cs index deeb5e544..76187b8f2 100755 --- a/QuickFIX.NET/SocketReader.cs +++ b/QuickFIX.NET/SocketReader.cs @@ -31,7 +31,12 @@ public void Read() int bytesRead = tcpClient_.Client.Receive(readBuffer_); if (0 == bytesRead) throw new SocketException(System.Convert.ToInt32(SocketError.ConnectionReset)); - OnMessageFound(System.Text.Encoding.UTF8.GetString(readBuffer_, 0, bytesRead)); + + string msg; + string buf = System.Text.Encoding.UTF8.GetString(readBuffer_, 0, bytesRead); + while (ReadFixMessage(out msg, out buf, buf)) + OnMessageFound(msg); + //parser_.AddToStream(System.Text.Encoding.UTF8.GetString(readBuffer_, 0, bytesRead)); } else if (null != qfSession_) @@ -50,6 +55,28 @@ public void Read() } } + /// FIXME move to Parser + public bool ReadFixMessage(out string msg, out string outbuf, string inbuf) + { + msg = ""; + outbuf = inbuf; + int pos = 0; + + pos = inbuf.IndexOf("\x01"+"10=", pos); + if (-1 == pos) + return false; + pos += 4; + + pos = inbuf.IndexOf("\x01", pos); + if (-1 == pos) + return false; + pos += 1; + + msg = inbuf.Substring(0, pos); + outbuf = inbuf.Remove(0, pos); + return true; + } + public void OnMessageFound(string msg) { try diff --git a/QuickFIX.NET/Values.cs b/QuickFIX.NET/Values.cs index 48930ebf4..17cd37cf8 100755 --- a/QuickFIX.NET/Values.cs +++ b/QuickFIX.NET/Values.cs @@ -10,7 +10,5 @@ public class Values public const string BeginString_FIX42 = "FIX.4.2"; public const string BeginString_FIX41 = "FIX.4.1"; public const string BeginString_FIX40 = "FIX.4.0"; - - public const string SessionRejectReason_VALUE_IS_INCORRECT_TEXT = "Value is incorrect (out of range) for this tag"; } } diff --git a/acceptance_test.bat b/acceptance_test.bat index 4041ee663..c68f96695 100755 --- a/acceptance_test.bat +++ b/acceptance_test.bat @@ -2,7 +2,7 @@ set RESULT=0 pushd AcceptanceTest del TestResult.xml AcceptanceTests.html - call runat release 5001 > TestResult.xml + call runat release 5001 if ERRORLEVEL 1 set RESULT=1 xsltproc.exe -o AcceptanceTests.html at.xsl TestResult.xml popd