From f93464016270bc843745aaa335d32cd289d057f2 Mon Sep 17 00:00:00 2001 From: Chris Busbey <cbusbey@connamara.com> Date: Wed, 17 Aug 2016 15:38:04 -0500 Subject: [PATCH] reject logon support --- errors.go | 20 ++++++++++++++++++-- logon_state.go | 19 ++++++++++++++++++- logon_state_test.go | 32 ++++++++++++++++++++++++++++---- session.go | 8 +++++++- session_test.go | 8 ++++---- 5 files changed, 75 insertions(+), 12 deletions(-) diff --git a/errors.go b/errors.go index c384211c..af949ebd 100644 --- a/errors.go +++ b/errors.go @@ -5,8 +5,8 @@ import ( "fmt" ) -//DoNotSend is a convenience error to indicate a DoNotSend in ToApp -var DoNotSend = errors.New("Do Not Send") +//ErrDoNotSend is a convenience error to indicate a DoNotSend in ToApp +var ErrDoNotSend = errors.New("Do Not Send") //rejectReason enum values. const ( @@ -37,6 +37,22 @@ type MessageRejectError interface { IsBusinessReject() bool } +//RejectLogon indicates the application is rejecting permission to logon. Implements MessageRejectError +type RejectLogon struct { + Text string +} + +func (e RejectLogon) Error() string { return e.Text } + +//RefTagID implements MessageRejectError +func (RejectLogon) RefTagID() *Tag { return nil } + +//RejectReason implements MessageRejectError +func (RejectLogon) RejectReason() int { return 0 } + +//IsBusinessReject implements MessageRejectError +func (RejectLogon) IsBusinessReject() bool { return false } + type messageRejectError struct { rejectReason int text string diff --git a/logon_state.go b/logon_state.go index b70e4f5a..88e69bda 100644 --- a/logon_state.go +++ b/logon_state.go @@ -21,7 +21,24 @@ func (s logonState) FixMsgIn(session *session, msg Message) (nextState sessionSt } if err := session.handleLogon(msg); err != nil { - return handleStateError(session, err) + switch err := err.(type) { + case RejectLogon: + session.log.OnEvent(err.Text) + msg := session.buildLogout(err.Text) + + if err := session.dropAndSend(msg, false); err != nil { + session.logError(err) + } + + if err := session.store.IncrNextTargetMsgSeqNum(); err != nil { + session.logError(err) + } + + return latentState{} + + default: + return handleStateError(session, err) + } } return inSession{} } diff --git a/logon_state_test.go b/logon_state_test.go index 19f1915d..30f56cfd 100644 --- a/logon_state_test.go +++ b/logon_state_test.go @@ -66,9 +66,9 @@ func (s *LogonStateTestSuite) TestFixMsgInNotLogon() { } func (s *LogonStateTestSuite) TestFixMsgInLogon() { - s.store.IncrNextSenderMsgSeqNum() + s.Require().Nil(s.store.IncrNextSenderMsgSeqNum()) s.MessageFactory.seqNum = 1 - s.store.IncrNextTargetMsgSeqNum() + s.Require().Nil(s.store.IncrNextTargetMsgSeqNum()) logon := s.Logon() logon.Body.SetField(tagHeartBtInt, FIXInt(32)) @@ -93,9 +93,9 @@ func (s *LogonStateTestSuite) TestFixMsgInLogon() { func (s *LogonStateTestSuite) TestFixMsgInLogonInitiateLogon() { s.session.InitiateLogon = true - s.store.IncrNextSenderMsgSeqNum() + s.Require().Nil(s.store.IncrNextSenderMsgSeqNum()) s.MessageFactory.seqNum = 1 - s.store.IncrNextTargetMsgSeqNum() + s.Require().Nil(s.store.IncrNextTargetMsgSeqNum()) logon := s.Logon() logon.Body.SetField(tagHeartBtInt, FIXInt(32)) @@ -150,3 +150,27 @@ func (s *LogonStateTestSuite) TestStop() { s.Stopped() } } + +func (s *LogonStateTestSuite) TestFixMsgInLogonRejectLogon() { + s.Require().Nil(s.store.IncrNextSenderMsgSeqNum()) + s.MessageFactory.seqNum = 1 + s.Require().Nil(s.store.IncrNextTargetMsgSeqNum()) + + logon := s.Logon() + logon.Body.SetField(tagHeartBtInt, FIXInt(32)) + + s.MockApp.On("FromAdmin").Return(RejectLogon{"reject message"}) + s.MockApp.On("ToAdmin") + s.fixMsgIn(s.session, logon) + + s.MockApp.AssertExpectations(s.T()) + + s.State(latentState{}) + + s.LastToAdminMessageSent() + s.MessageType(enum.MsgType_LOGOUT, s.MockApp.lastToAdmin) + s.FieldEquals(tagText, "reject message", s.MockApp.lastToAdmin.Body) + + s.NextTargetMsgSeqNum(3) + s.NextSenderMsgSeqNum(3) +} diff --git a/session.go b/session.go index d161a6a4..a159ff7e 100644 --- a/session.go +++ b/session.go @@ -128,7 +128,7 @@ func (s *session) sendLogon(resetStore, setResetSeqNum bool) error { return nil } -func (s *session) sendLogout(reason string) error { +func (s *session) buildLogout(reason string) Message { logout := NewMessage() logout.Header.SetField(tagMsgType, FIXString("5")) logout.Header.SetField(tagBeginString, FIXString(s.sessionID.BeginString)) @@ -137,6 +137,12 @@ func (s *session) sendLogout(reason string) error { if reason != "" { logout.Body.SetField(tagText, FIXString(reason)) } + + return logout +} + +func (s *session) sendLogout(reason string) error { + logout := s.buildLogout(reason) return s.send(logout) } diff --git a/session_test.go b/session_test.go index a2485ddf..b1cb64c4 100644 --- a/session_test.go +++ b/session_test.go @@ -611,8 +611,8 @@ func (suite *SessionSendTestSuite) TestQueueForSendAppMessage() { } func (suite *SessionSendTestSuite) TestQueueForSendDoNotSendAppMessage() { - suite.MockApp.On("ToApp").Return(DoNotSend) - suite.Equal(DoNotSend, suite.queueForSend(suite.NewOrderSingle())) + suite.MockApp.On("ToApp").Return(ErrDoNotSend) + suite.Equal(ErrDoNotSend, suite.queueForSend(suite.NewOrderSingle())) suite.MockApp.AssertExpectations(suite.T()) suite.NoMessagePersisted(1) @@ -649,8 +649,8 @@ func (suite *SessionSendTestSuite) TestSendAppMessage() { } func (suite *SessionSendTestSuite) TestSendAppDoNotSendMessage() { - suite.MockApp.On("ToApp").Return(DoNotSend) - suite.Equal(DoNotSend, suite.send(suite.NewOrderSingle())) + suite.MockApp.On("ToApp").Return(ErrDoNotSend) + suite.Equal(ErrDoNotSend, suite.send(suite.NewOrderSingle())) suite.MockApp.AssertExpectations(suite.T()) suite.NextSenderMsgSeqNum(1) -- GitLab