diff --git a/in_session_test.go b/in_session_test.go index b73dc9d1c..dde812380 100644 --- a/in_session_test.go +++ b/in_session_test.go @@ -19,17 +19,12 @@ func TestInSessionTestSuite(t *testing.T) { func (s *InSessionTestSuite) SetupTest() { s.Init() s.session.State = inSession{} + s.session.messageStash = make(map[int]Message) } -func (s *InSessionTestSuite) TestIsLoggedOn() { +func (s *InSessionTestSuite) TestPreliminary() { s.True(s.session.IsLoggedOn()) -} - -func (s *InSessionTestSuite) TestIsConnected() { s.True(s.session.IsConnected()) -} - -func (s *InSessionTestSuite) TestIsSessionTime() { s.True(s.session.IsSessionTime()) } @@ -115,3 +110,26 @@ func (s *InSessionTestSuite) TestStop() { s.Stopped() s.Disconnected() } + +func (s *InSessionTestSuite) TestFIXMsgInTargetTooHigh() { + s.MessageFactory.seqNum = 5 + + s.MockApp.On("ToAdmin") + msgSeqNumTooHigh := s.NewOrderSingle() + s.fixMsgIn(s.session, msgSeqNumTooHigh) + + s.MockApp.AssertExpectations(s.T()) + s.LastToAdminMessageSent() + s.MessageType(enum.MsgType_RESEND_REQUEST, s.MockApp.lastToAdmin) + s.FieldEquals(tagBeginSeqNo, 1, s.MockApp.lastToAdmin.Body) + + s.State(resendState{}) + s.NextTargetMsgSeqNum(1) + + stashedMsg, ok := s.session.messageStash[6] + s.True(ok) + + rawMsg, _ := msgSeqNumTooHigh.Build() + stashedRawMsg, _ := stashedMsg.Build() + s.Equal(string(rawMsg), string(stashedRawMsg)) +} diff --git a/quickfix_test.go b/quickfix_test.go index a8fc4a2b9..c2cee6b8e 100644 --- a/quickfix_test.go +++ b/quickfix_test.go @@ -104,6 +104,10 @@ type MessageFactory struct { seqNum int } +func (m *MessageFactory) SetNextSeqNum(next int) { + m.seqNum = next - 1 +} + func (m *MessageFactory) buildMessage(msgType string) Message { m.seqNum++ msg := NewMessage() diff --git a/resend_state.go b/resend_state.go index 15254d874..0f3669d5e 100644 --- a/resend_state.go +++ b/resend_state.go @@ -23,14 +23,22 @@ func (s resendState) Timeout(session *session, event internal.Event) (nextState func (s resendState) FixMsgIn(session *session, msg Message) (nextState sessionState) { nextState = inSession{}.FixMsgIn(session, msg) - if !nextState.IsLoggedOn() || len(session.messageStash) == 0 { + if _, stillInResend := nextState.(resendState); stillInResend || !nextState.IsLoggedOn() { return } - targetSeqNum := session.store.NextTargetMsgSeqNum() - if msg, ok := session.messageStash[targetSeqNum]; ok { + for len(session.messageStash) > 0 { + targetSeqNum := session.store.NextTargetMsgSeqNum() + msg, ok := session.messageStash[targetSeqNum] + if !ok { + return s + } delete(session.messageStash, targetSeqNum) - nextState = nextState.FixMsgIn(session, msg) + + nextState = inSession{}.FixMsgIn(session, msg) + if !nextState.IsLoggedOn() { + return + } } return diff --git a/resend_state_test.go b/resend_state_test.go index 41f28e8ba..401d2b274 100644 --- a/resend_state_test.go +++ b/resend_state_test.go @@ -3,6 +3,7 @@ package quickfix import ( "testing" + "github.com/quickfixgo/quickfix/enum" "github.com/quickfixgo/quickfix/internal" "github.com/stretchr/testify/suite" ) @@ -18,6 +19,7 @@ func TestResendStateTestSuite(t *testing.T) { func (s *resendStateTestSuite) SetupTest() { s.Init() s.session.State = resendState{} + s.session.messageStash = make(map[int]Message) } func (s *resendStateTestSuite) TestIsLoggedOn() { @@ -56,3 +58,40 @@ func (s *resendStateTestSuite) TestTimeoutUnchangedNeedHeartbeat() { s.MockApp.AssertExpectations(s.T()) s.State(resendState{}) } + +func (s *resendStateTestSuite) TestFixMsgIn() { + s.session.State = inSession{} + + //in session expects seq number 1, send too high + s.MessageFactory.SetNextSeqNum(2) + s.MockApp.On("ToAdmin") + + msgSeqNum2 := s.NewOrderSingle() + s.fixMsgIn(s.session, msgSeqNum2) + + s.MockApp.AssertExpectations(s.T()) + s.State(resendState{}) + s.LastToAdminMessageSent() + s.MessageType(enum.MsgType_RESEND_REQUEST, s.MockApp.lastToAdmin) + s.FieldEquals(tagBeginSeqNo, 1, s.MockApp.lastToAdmin.Body) + s.NextTargetMsgSeqNum(1) + + msgSeqNum3 := s.NewOrderSingle() + s.fixMsgIn(s.session, msgSeqNum3) + s.State(resendState{}) + s.NextTargetMsgSeqNum(1) + + msgSeqNum4 := s.NewOrderSingle() + s.fixMsgIn(s.session, msgSeqNum4) + + s.State(resendState{}) + s.NextTargetMsgSeqNum(1) + + s.MessageFactory.SetNextSeqNum(1) + s.MockApp.On("FromApp").Return(nil) + s.fixMsgIn(s.session, s.NewOrderSingle()) + + s.MockApp.AssertNumberOfCalls(s.T(), "FromApp", 4) + s.State(inSession{}) + s.NextTargetMsgSeqNum(5) +}