From 44f63ae00d48d393e59d9656de2b11e2d93efad1 Mon Sep 17 00:00:00 2001 From: zee276 Date: Thu, 16 Oct 2025 10:57:38 +0200 Subject: [PATCH 1/5] handle logon error --- acceptor.go | 6 ++++-- connection.go | 21 ++++++++++++++++++--- connection_internal_test.go | 7 +++++-- initiator.go | 27 ++++++++++++++++----------- session.go | 10 +++++----- session_state.go | 11 ++++++----- 6 files changed, 54 insertions(+), 28 deletions(-) diff --git a/acceptor.go b/acceptor.go index f58ef01f7..0228778c1 100644 --- a/acceptor.go +++ b/acceptor.go @@ -18,6 +18,7 @@ package quickfix import ( "bufio" "bytes" + "context" "crypto/tls" "io" "net" @@ -361,6 +362,7 @@ func (a *Acceptor) handleConnection(netConn net.Conn) { a.sessionAddr.Store(sessID, netConn.RemoteAddr()) msgIn := make(chan fixIn) msgOut := make(chan []byte) + ctx := context.Background() if err := session.connect(msgIn, msgOut); err != nil { a.globalLog.OnEventf("Unable to accept session %v connection: %v", sessID, err.Error()) @@ -369,10 +371,10 @@ func (a *Acceptor) handleConnection(netConn net.Conn) { go func() { msgIn <- fixIn{msgBytes, parser.lastRead} - readLoop(parser, msgIn, a.globalLog) + readLoop(ctx, parser, msgIn, a.globalLog) }() - writeLoop(netConn, msgOut, a.globalLog) + writeLoop(ctx, netConn, msgOut, a.globalLog) } func (a *Acceptor) dynamicSessionsLoop() { diff --git a/connection.go b/connection.go index 99a4c465e..95e77b239 100644 --- a/connection.go +++ b/connection.go @@ -15,10 +15,19 @@ package quickfix -import "io" +import ( + "context" + "io" +) -func writeLoop(connection io.Writer, messageOut chan []byte, log Log) { +func writeLoop(ctx context.Context, connection io.Writer, messageOut chan []byte, log Log) { for { + select { + case <-ctx.Done(): + return + default: + } + msg, ok := <-messageOut if !ok { return @@ -30,10 +39,16 @@ func writeLoop(connection io.Writer, messageOut chan []byte, log Log) { } } -func readLoop(parser *parser, msgIn chan fixIn, log Log) { +func readLoop(ctx context.Context, parser *parser, msgIn chan fixIn, log Log) { defer close(msgIn) for { + select { + case <-ctx.Done(): + return + default: + } + msg, err := parser.ReadMessage() if err != nil { log.OnEvent(err.Error()) diff --git a/connection_internal_test.go b/connection_internal_test.go index 081b3c110..daa045dd0 100644 --- a/connection_internal_test.go +++ b/connection_internal_test.go @@ -17,11 +17,13 @@ package quickfix import ( "bytes" + "context" "strings" "testing" ) func TestWriteLoop(t *testing.T) { + ctx := context.Background() writer := bytes.NewBufferString("") msgOut := make(chan []byte) @@ -31,7 +33,7 @@ func TestWriteLoop(t *testing.T) { msgOut <- []byte("test msg 3") close(msgOut) }() - writeLoop(writer, msgOut, nullLog{}) + writeLoop(ctx, writer, msgOut, nullLog{}) expected := "test msg 1 test msg 2 test msg 3" @@ -41,11 +43,12 @@ func TestWriteLoop(t *testing.T) { } func TestReadLoop(t *testing.T) { + ctx := context.Background() msgIn := make(chan fixIn) stream := "hello8=FIX.4.09=5blah10=103garbage8=FIX.4.09=4foo10=103" parser := newParser(strings.NewReader(stream)) - go readLoop(parser, msgIn, nullLog{}) + go readLoop(ctx, parser, msgIn, nullLog{}) var tests = []struct { expectedMsg string diff --git a/initiator.go b/initiator.go index 18451477e..991001320 100644 --- a/initiator.go +++ b/initiator.go @@ -163,14 +163,17 @@ func (i *Initiator) handleConnection(session *session, tlsConfig *tls.Config, di return } - ctx, cancel := context.WithCancel(context.Background()) + ctx := context.Background() + dialCtx, dialCancel := context.WithCancel(ctx) + readWriteCtx, readWriteCancel := context.WithCancel(ctx) // We start a goroutine in order to be able to cancel the dialer mid-connection // on receiving a stop signal to stop the initiator. go func() { select { case <-i.stopChan: - cancel() + dialCancel() + readWriteCancel() case <-ctx.Done(): return } @@ -183,7 +186,7 @@ func (i *Initiator) handleConnection(session *session, tlsConfig *tls.Config, di address := session.SocketConnectAddress[connectionAttempt%len(session.SocketConnectAddress)] session.log.OnEventf("Connecting to: %v", address) - netConn, err := dialer.DialContext(ctx, "tcp", address) + netConn, err := dialer.DialContext(dialCtx, "tcp", address) if err != nil { session.log.OnEventf("Failed to connect: %v", err) goto reconnect @@ -207,24 +210,26 @@ func (i *Initiator) handleConnection(session *session, tlsConfig *tls.Config, di msgIn = make(chan fixIn) msgOut = make(chan []byte) - if err := session.connect(msgIn, msgOut); err != nil { - session.log.OnEventf("Failed to initiate: %v", err) - goto reconnect - } + - go readLoop(newParser(bufio.NewReader(netConn)), msgIn, session.log) + go readLoop(readWriteCtx,newParser(bufio.NewReader(netConn)), msgIn, session.log) disconnected = make(chan interface{}) go func() { - writeLoop(netConn, msgOut, session.log) + writeLoop(readWriteCtx,netConn, msgOut, session.log) if err := netConn.Close(); err != nil { session.log.OnEvent(err.Error()) } close(disconnected) }() + if err := session.connect(msgIn, msgOut); err != nil { + session.log.OnEventf("Failed to initiate: %v", err) + goto reconnect + } + // This ensures we properly cleanup the goroutine and context used for // dial cancelation after successful connection. - cancel() + dialCancel() select { case <-disconnected: @@ -233,7 +238,7 @@ func (i *Initiator) handleConnection(session *session, tlsConfig *tls.Config, di } reconnect: - cancel() + dialCancel() connectionAttempt++ session.log.OnEventf("Reconnecting in %v", session.ReconnectInterval) diff --git a/session.go b/session.go index a6d296999..27a06b625 100644 --- a/session.go +++ b/session.go @@ -849,15 +849,15 @@ func (s *session) onAdmin(msg interface{}) { return } - if msg.err != nil { - close(msg.err) - } - s.messageIn = msg.messageIn s.messageOut = msg.messageOut s.sentReset = false - s.Connect(s) + err := s.Connect(s) + if msg.err != nil { + msg.err <- err + close(msg.err) + } case stopReq: s.Stop(s) diff --git a/session_state.go b/session_state.go index 6fe4dded7..509803a0e 100644 --- a/session_state.go +++ b/session_state.go @@ -36,36 +36,37 @@ func (sm *stateMachine) Start(s *session) { sm.CheckSessionTime(s, time.Now()) } -func (sm *stateMachine) Connect(session *session) { +func (sm *stateMachine) Connect(session *session) error{ // No special logon logic needed for FIX Acceptors. if !session.InitiateLogon { sm.setState(session, logonState{}) - return + return nil } if session.RefreshOnLogon { if err := session.store.Refresh(); err != nil { session.logError(err) - return + return err } } if session.ResetOnLogon { if err := session.store.Reset(); err != nil { session.logError(err) - return + return err } } session.log.OnEvent("Sending logon request") if err := session.sendLogon(); err != nil { session.logError(err) - return + return err } sm.setState(session, logonState{}) // Fire logon timeout event after the pre-configured delay period. time.AfterFunc(session.LogonTimeout, func() { session.sessionEvent <- internal.LogonTimeout }) + return nil } func (sm *stateMachine) Stop(session *session) { From 5fa869ee2e6c4d3c8a3ff59540ad68b25199648b Mon Sep 17 00:00:00 2001 From: zee276 Date: Wed, 22 Oct 2025 09:57:41 +0200 Subject: [PATCH 2/5] add tests --- connection_internal_test.go | 36 +++++++- initiator_test.go | 172 ++++++++++++++++++++++++++++++++++++ session_test.go | 23 +++++ 3 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 initiator_test.go diff --git a/connection_internal_test.go b/connection_internal_test.go index daa045dd0..3396c007e 100644 --- a/connection_internal_test.go +++ b/connection_internal_test.go @@ -42,8 +42,27 @@ func TestWriteLoop(t *testing.T) { } } +func TestWriteLoopCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + writer := bytes.NewBufferString("") + msgOut := make(chan []byte) + + go func() { + msgOut <- []byte("test msg 1") + cancel() + }() + writeLoop(ctx, writer, msgOut, nullLog{}) + + expected := "test msg 1" + + if writer.String() != expected { + t.Errorf("expected %v got %v", expected, writer.String()) + } +} + func TestReadLoop(t *testing.T) { - ctx := context.Background() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() msgIn := make(chan fixIn) stream := "hello8=FIX.4.09=5blah10=103garbage8=FIX.4.09=4foo10=103" @@ -74,3 +93,18 @@ func TestReadLoop(t *testing.T) { } } } + +func TestReadLoopCancel(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + msgIn := make(chan fixIn) + stream := "hello8=FIX.4.09=5blah10=103garbage8=FIX.4.09=4foo10=103" + + parser := newParser(strings.NewReader(stream)) + + cancel() + go readLoop(ctx, parser, msgIn, nullLog{}) + _, ok := <-msgIn + if ok { + t.Error("Channel should be closed on context cancel") + } +} diff --git a/initiator_test.go b/initiator_test.go new file mode 100644 index 000000000..72b1d03c8 --- /dev/null +++ b/initiator_test.go @@ -0,0 +1,172 @@ +package quickfix + +import ( + "context" + "errors" + "net" + "testing" + "time" + + "github.com/quickfixgo/quickfix/config" +) + +func TestNewInitiatorKeepReconnectingAfterLogonError(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + logonCount := 0 + app := &mockApplication{} + storeFactory := &mockMessageStoreFactory{saveMessageAndIncrError: errDBError} + logFactory := &mockLogFactory{ + onEvent: func(s string) { + if s == "Sending logon request" { + logonCount++ + if logonCount >= 5 { + cancel() + } + } + }, + } + + settings := NewSettings() + sessionSettings := newSession() + sessionID,err :=settings.AddSession(sessionSettings) + if err != nil { + t.Fatalf("Expected no error adding session, got %v", err) + } + + initiator, err := NewInitiator(app, storeFactory, settings, logFactory) + if err != nil { + t.Fatalf("Expected no error, got %v", err) + } + + s, ok := initiator.sessions[sessionID] + if !ok { + t.Fatal("Expected session to be created") + } + + initiator.stopChan = make(chan interface{}) + go initiator.handleConnection(s,nil,&mockDialer{}) + + + select { + case <-ctx.Done(): + initiator.Stop() + return + case <-time.After(10 * time.Second): + t.Error("retry stopped after logon error") + return + } +} + +func newSession() *SessionSettings { + sessionSettings := NewSessionSettings() + sessionSettings.Set(config.BeginString, "FIX.4.4") + sessionSettings.Set(config.SenderCompID, "X") + sessionSettings.Set(config.TargetCompID, "X") + sessionSettings.Set(config.HeartBtInt, "30") + sessionSettings.Set(config.SocketConnectHost, "localhost") + sessionSettings.Set(config.SocketConnectPort, "9878") + sessionSettings.Set(config.ReconnectInterval, "1") + return sessionSettings +} + +type mockApplication struct{} + +func (m *mockApplication) OnCreate(sessionID SessionID) {} +func (m *mockApplication) OnLogon(sessionID SessionID) {} +func (m *mockApplication) OnLogout(sessionID SessionID) {} +func (m *mockApplication) ToAdmin(message *Message, sessionID SessionID) {} +func (m *mockApplication) ToApp(message *Message, sessionID SessionID) error { return nil } +func (m *mockApplication) FromAdmin(message *Message, sessionID SessionID) MessageRejectError { return nil } +func (m *mockApplication) FromApp(message *Message, sessionID SessionID) MessageRejectError { return nil } + +type mockMessageStoreFactory struct{ + saveMessageAndIncrError error +} + +func (m *mockMessageStoreFactory) Create(sessionID SessionID) (MessageStore, error) { + return &mockMessageStore{saveMessageAndIncrError: m.saveMessageAndIncrError}, nil +} + +var errDBError = errors.New("db error") + +type mockMessageStore struct{ + saveMessageAndIncrError error +} + +func (m *mockMessageStore) NextSenderMsgSeqNum() int { return 1 } +func (m *mockMessageStore) NextTargetMsgSeqNum() int { return 1 } +func (m *mockMessageStore) IncrSenderMsgSeqNum() error { return nil } +func (m *mockMessageStore) IncrTargetMsgSeqNum() error { return nil } +func (m *mockMessageStore) SetNextSenderMsgSeqNum(next int) error { return nil } +func (m *mockMessageStore) SetNextTargetMsgSeqNum(next int) error { return nil } +func (m *mockMessageStore) CreationTime() time.Time { return time.Now() } +func (m *mockMessageStore) SaveMessage(seqNum int, msg []byte) error { return nil } +func (m *mockMessageStore) GetMessages(beginSeqNum, endSeqNum int) ([][]byte, error) { return nil, nil } +func (m *mockMessageStore) Refresh() error { return nil } +func (m *mockMessageStore) Reset() error { return nil } +func (m *mockMessageStore) Close() error { return nil } +func (m *mockMessageStore) IncrNextSenderMsgSeqNum() error {return nil} +func (m *mockMessageStore) IncrNextTargetMsgSeqNum() error {return nil} +func (m *mockMessageStore) IterateMessages(int, int, func([]byte) error) error {return nil} +func (m *mockMessageStore) SaveMessageAndIncrNextSenderMsgSeqNum(seqNum int, msg []byte) error { return m.saveMessageAndIncrError } +func (m *mockMessageStore) SetCreationTime(time.Time) {} + +type mockLogFactory struct { + shouldFail bool + onEvent func(string) +} + +func (m *mockLogFactory) Create() (Log, error) { + if m.shouldFail { + return nil, errors.New("log factory error") + } + return &mockLog{ + onEvent: m.onEvent, + }, nil +} + +func (m *mockLogFactory) CreateSessionLog(sessionID SessionID) (Log, error) { + return &mockLog{ + onEvent: m.onEvent, + }, nil +} + +type mockDialer struct{} + +type mockAddr struct { + network string + address string +} + +func (m *mockAddr) Network() string { return m.network } +func (m *mockAddr) String() string { return m.address } + +type mockConn struct {} + +func (m *mockConn) Read(b []byte) (n int, err error) { return 0, nil } +func (m *mockConn) Write(b []byte) (n int, err error) { return len(b), nil } +func (m *mockConn) Close() error { return nil } +func (m *mockConn) LocalAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:8080"} } +func (m *mockConn) RemoteAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:9090"} } +func (m *mockConn) SetDeadline(t time.Time) error { return nil } +func (m *mockConn) SetReadDeadline(t time.Time) error { return nil } +func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil } + +func (m *mockDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error){ + return &mockConn{}, nil +} + +type mockLog struct{ + onEvent func(string) +} + +func (m *mockLog) OnIncoming(s []byte) {} +func (m *mockLog) OnOutgoing(s []byte) {} +func (m *mockLog) OnEvent(s string) { + if m.onEvent != nil { + m.onEvent(s) + } +} +func (m *mockLog) OnEventf(format string, a ...interface{}) {} \ No newline at end of file diff --git a/session_test.go b/session_test.go index 2ea5c3508..09a371818 100644 --- a/session_test.go +++ b/session_test.go @@ -17,6 +17,7 @@ package quickfix import ( "bytes" + "fmt" "testing" "time" @@ -743,6 +744,28 @@ func (s *SessionSuite) TestOnAdminConnectRefreshOnLogon() { } } +func (s *SessionSuite) TestOnAdminConnectError() { + dbError := fmt.Errorf("db error") + s.SetupTest() + errChannel := make(chan error, 1) + s.session.RefreshOnLogon = true + adminMsg := connect{ + messageOut: s.Receiver.sendChannel, + err: errChannel, + } + s.session.State = latentState{} + s.session.InitiateLogon = true + s.MockStore.On("Refresh").Return(dbError) + s.MockApp.On("ToAdmin") + s.session.onAdmin(adminMsg) + + err := <-errChannel + s.Assert().Equal(err, dbError) + + s.MockStore.AssertExpectations(s.T()) + +} + func (s *SessionSuite) TestOnAdminConnectAccept() { adminMsg := connect{ messageOut: s.Receiver.sendChannel, From 83c4e63a2861be8c4ba3507c4e44be951f9075a2 Mon Sep 17 00:00:00 2001 From: zee276 Date: Fri, 24 Oct 2025 11:51:14 +0200 Subject: [PATCH 3/5] fix lint errors --- initiator.go | 5 +-- initiator_test.go | 97 +++++++++++++++++++++++++---------------------- session_state.go | 2 +- 3 files changed, 54 insertions(+), 50 deletions(-) diff --git a/initiator.go b/initiator.go index 991001320..f62b1f1d1 100644 --- a/initiator.go +++ b/initiator.go @@ -210,12 +210,11 @@ func (i *Initiator) handleConnection(session *session, tlsConfig *tls.Config, di msgIn = make(chan fixIn) msgOut = make(chan []byte) - - go readLoop(readWriteCtx,newParser(bufio.NewReader(netConn)), msgIn, session.log) + go readLoop(readWriteCtx, newParser(bufio.NewReader(netConn)), msgIn, session.log) disconnected = make(chan interface{}) go func() { - writeLoop(readWriteCtx,netConn, msgOut, session.log) + writeLoop(readWriteCtx, netConn, msgOut, session.log) if err := netConn.Close(); err != nil { session.log.OnEvent(err.Error()) } diff --git a/initiator_test.go b/initiator_test.go index 72b1d03c8..cba9eb862 100644 --- a/initiator_test.go +++ b/initiator_test.go @@ -27,10 +27,10 @@ func TestNewInitiatorKeepReconnectingAfterLogonError(t *testing.T) { } }, } - + settings := NewSettings() sessionSettings := newSession() - sessionID,err :=settings.AddSession(sessionSettings) + sessionID, err := settings.AddSession(sessionSettings) if err != nil { t.Fatalf("Expected no error adding session, got %v", err) } @@ -46,16 +46,15 @@ func TestNewInitiatorKeepReconnectingAfterLogonError(t *testing.T) { } initiator.stopChan = make(chan interface{}) - go initiator.handleConnection(s,nil,&mockDialer{}) - + go initiator.handleConnection(s, nil, &mockDialer{}) select { - case <-ctx.Done(): - initiator.Stop() - return - case <-time.After(10 * time.Second): - t.Error("retry stopped after logon error") - return + case <-ctx.Done(): + initiator.Stop() + return + case <-time.After(10 * time.Second): + t.Error("retry stopped after logon error") + return } } @@ -73,15 +72,19 @@ func newSession() *SessionSettings { type mockApplication struct{} -func (m *mockApplication) OnCreate(sessionID SessionID) {} -func (m *mockApplication) OnLogon(sessionID SessionID) {} -func (m *mockApplication) OnLogout(sessionID SessionID) {} -func (m *mockApplication) ToAdmin(message *Message, sessionID SessionID) {} -func (m *mockApplication) ToApp(message *Message, sessionID SessionID) error { return nil } -func (m *mockApplication) FromAdmin(message *Message, sessionID SessionID) MessageRejectError { return nil } -func (m *mockApplication) FromApp(message *Message, sessionID SessionID) MessageRejectError { return nil } +func (m *mockApplication) OnCreate(sessionID SessionID) {} +func (m *mockApplication) OnLogon(sessionID SessionID) {} +func (m *mockApplication) OnLogout(sessionID SessionID) {} +func (m *mockApplication) ToAdmin(message *Message, sessionID SessionID) {} +func (m *mockApplication) ToApp(message *Message, sessionID SessionID) error { return nil } +func (m *mockApplication) FromAdmin(message *Message, sessionID SessionID) MessageRejectError { + return nil +} +func (m *mockApplication) FromApp(message *Message, sessionID SessionID) MessageRejectError { + return nil +} -type mockMessageStoreFactory struct{ +type mockMessageStoreFactory struct { saveMessageAndIncrError error } @@ -91,31 +94,33 @@ func (m *mockMessageStoreFactory) Create(sessionID SessionID) (MessageStore, err var errDBError = errors.New("db error") -type mockMessageStore struct{ +type mockMessageStore struct { saveMessageAndIncrError error } -func (m *mockMessageStore) NextSenderMsgSeqNum() int { return 1 } -func (m *mockMessageStore) NextTargetMsgSeqNum() int { return 1 } -func (m *mockMessageStore) IncrSenderMsgSeqNum() error { return nil } -func (m *mockMessageStore) IncrTargetMsgSeqNum() error { return nil } -func (m *mockMessageStore) SetNextSenderMsgSeqNum(next int) error { return nil } -func (m *mockMessageStore) SetNextTargetMsgSeqNum(next int) error { return nil } -func (m *mockMessageStore) CreationTime() time.Time { return time.Now() } -func (m *mockMessageStore) SaveMessage(seqNum int, msg []byte) error { return nil } +func (m *mockMessageStore) NextSenderMsgSeqNum() int { return 1 } +func (m *mockMessageStore) NextTargetMsgSeqNum() int { return 1 } +func (m *mockMessageStore) IncrSenderMsgSeqNum() error { return nil } +func (m *mockMessageStore) IncrTargetMsgSeqNum() error { return nil } +func (m *mockMessageStore) SetNextSenderMsgSeqNum(next int) error { return nil } +func (m *mockMessageStore) SetNextTargetMsgSeqNum(next int) error { return nil } +func (m *mockMessageStore) CreationTime() time.Time { return time.Now() } +func (m *mockMessageStore) SaveMessage(seqNum int, msg []byte) error { return nil } func (m *mockMessageStore) GetMessages(beginSeqNum, endSeqNum int) ([][]byte, error) { return nil, nil } -func (m *mockMessageStore) Refresh() error { return nil } -func (m *mockMessageStore) Reset() error { return nil } -func (m *mockMessageStore) Close() error { return nil } -func (m *mockMessageStore) IncrNextSenderMsgSeqNum() error {return nil} -func (m *mockMessageStore) IncrNextTargetMsgSeqNum() error {return nil} -func (m *mockMessageStore) IterateMessages(int, int, func([]byte) error) error {return nil} -func (m *mockMessageStore) SaveMessageAndIncrNextSenderMsgSeqNum(seqNum int, msg []byte) error { return m.saveMessageAndIncrError } +func (m *mockMessageStore) Refresh() error { return nil } +func (m *mockMessageStore) Reset() error { return nil } +func (m *mockMessageStore) Close() error { return nil } +func (m *mockMessageStore) IncrNextSenderMsgSeqNum() error { return nil } +func (m *mockMessageStore) IncrNextTargetMsgSeqNum() error { return nil } +func (m *mockMessageStore) IterateMessages(int, int, func([]byte) error) error { return nil } +func (m *mockMessageStore) SaveMessageAndIncrNextSenderMsgSeqNum(seqNum int, msg []byte) error { + return m.saveMessageAndIncrError +} func (m *mockMessageStore) SetCreationTime(time.Time) {} type mockLogFactory struct { shouldFail bool - onEvent func(string) + onEvent func(string) } func (m *mockLogFactory) Create() (Log, error) { @@ -143,30 +148,30 @@ type mockAddr struct { func (m *mockAddr) Network() string { return m.network } func (m *mockAddr) String() string { return m.address } -type mockConn struct {} +type mockConn struct{} func (m *mockConn) Read(b []byte) (n int, err error) { return 0, nil } func (m *mockConn) Write(b []byte) (n int, err error) { return len(b), nil } func (m *mockConn) Close() error { return nil } -func (m *mockConn) LocalAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:8080"} } -func (m *mockConn) RemoteAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:9090"} } -func (m *mockConn) SetDeadline(t time.Time) error { return nil } -func (m *mockConn) SetReadDeadline(t time.Time) error { return nil } +func (m *mockConn) LocalAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:8080"} } +func (m *mockConn) RemoteAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:9090"} } +func (m *mockConn) SetDeadline(t time.Time) error { return nil } +func (m *mockConn) SetReadDeadline(t time.Time) error { return nil } func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil } -func (m *mockDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error){ +func (m *mockDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { return &mockConn{}, nil } -type mockLog struct{ +type mockLog struct { onEvent func(string) } -func (m *mockLog) OnIncoming(s []byte) {} -func (m *mockLog) OnOutgoing(s []byte) {} -func (m *mockLog) OnEvent(s string) { +func (m *mockLog) OnIncoming(s []byte) {} +func (m *mockLog) OnOutgoing(s []byte) {} +func (m *mockLog) OnEvent(s string) { if m.onEvent != nil { m.onEvent(s) } } -func (m *mockLog) OnEventf(format string, a ...interface{}) {} \ No newline at end of file +func (m *mockLog) OnEventf(format string, a ...interface{}) {} diff --git a/session_state.go b/session_state.go index 509803a0e..8d7182489 100644 --- a/session_state.go +++ b/session_state.go @@ -36,7 +36,7 @@ func (sm *stateMachine) Start(s *session) { sm.CheckSessionTime(s, time.Now()) } -func (sm *stateMachine) Connect(session *session) error{ +func (sm *stateMachine) Connect(session *session) error { // No special logon logic needed for FIX Acceptors. if !session.InitiateLogon { sm.setState(session, logonState{}) From 647f30f4a5169372c96c229a604b0cea4615418d Mon Sep 17 00:00:00 2001 From: zee276 Date: Fri, 24 Oct 2025 11:56:38 +0200 Subject: [PATCH 4/5] fix lint error --- session_test.go | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/session_test.go b/session_test.go index 09a371818..07e06ecbe 100644 --- a/session_test.go +++ b/session_test.go @@ -746,23 +746,23 @@ func (s *SessionSuite) TestOnAdminConnectRefreshOnLogon() { func (s *SessionSuite) TestOnAdminConnectError() { dbError := fmt.Errorf("db error") - s.SetupTest() - errChannel := make(chan error, 1) - s.session.RefreshOnLogon = true - adminMsg := connect{ - messageOut: s.Receiver.sendChannel, - err: errChannel, - } - s.session.State = latentState{} - s.session.InitiateLogon = true - s.MockStore.On("Refresh").Return(dbError) - s.MockApp.On("ToAdmin") - s.session.onAdmin(adminMsg) + s.SetupTest() + errChannel := make(chan error, 1) + s.session.RefreshOnLogon = true + adminMsg := connect{ + messageOut: s.Receiver.sendChannel, + err: errChannel, + } + s.session.State = latentState{} + s.session.InitiateLogon = true + s.MockStore.On("Refresh").Return(dbError) + s.MockApp.On("ToAdmin") + s.session.onAdmin(adminMsg) - err := <-errChannel - s.Assert().Equal(err, dbError) + err := <-errChannel + s.Assert().Equal(err, dbError) - s.MockStore.AssertExpectations(s.T()) + s.MockStore.AssertExpectations(s.T()) } From 4568b83d58eb886174633363c2bea7df11efb2f2 Mon Sep 17 00:00:00 2001 From: zee276 Date: Fri, 24 Oct 2025 12:09:22 +0200 Subject: [PATCH 5/5] fix revive lint warnings --- initiator_test.go | 68 +++++++++++++++++++++++------------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/initiator_test.go b/initiator_test.go index cba9eb862..1eb70dc34 100644 --- a/initiator_test.go +++ b/initiator_test.go @@ -72,15 +72,15 @@ func newSession() *SessionSettings { type mockApplication struct{} -func (m *mockApplication) OnCreate(sessionID SessionID) {} -func (m *mockApplication) OnLogon(sessionID SessionID) {} -func (m *mockApplication) OnLogout(sessionID SessionID) {} -func (m *mockApplication) ToAdmin(message *Message, sessionID SessionID) {} -func (m *mockApplication) ToApp(message *Message, sessionID SessionID) error { return nil } -func (m *mockApplication) FromAdmin(message *Message, sessionID SessionID) MessageRejectError { +func (m *mockApplication) OnCreate(_ SessionID) {} +func (m *mockApplication) OnLogon(_ SessionID) {} +func (m *mockApplication) OnLogout(_ SessionID) {} +func (m *mockApplication) ToAdmin(_ *Message, _ SessionID) {} +func (m *mockApplication) ToApp(_ *Message, _ SessionID) error { return nil } +func (m *mockApplication) FromAdmin(_ *Message, _ SessionID) MessageRejectError { return nil } -func (m *mockApplication) FromApp(message *Message, sessionID SessionID) MessageRejectError { +func (m *mockApplication) FromApp(_ *Message, _ SessionID) MessageRejectError { return nil } @@ -88,7 +88,7 @@ type mockMessageStoreFactory struct { saveMessageAndIncrError error } -func (m *mockMessageStoreFactory) Create(sessionID SessionID) (MessageStore, error) { +func (m *mockMessageStoreFactory) Create(_ SessionID) (MessageStore, error) { return &mockMessageStore{saveMessageAndIncrError: m.saveMessageAndIncrError}, nil } @@ -98,22 +98,22 @@ type mockMessageStore struct { saveMessageAndIncrError error } -func (m *mockMessageStore) NextSenderMsgSeqNum() int { return 1 } -func (m *mockMessageStore) NextTargetMsgSeqNum() int { return 1 } -func (m *mockMessageStore) IncrSenderMsgSeqNum() error { return nil } -func (m *mockMessageStore) IncrTargetMsgSeqNum() error { return nil } -func (m *mockMessageStore) SetNextSenderMsgSeqNum(next int) error { return nil } -func (m *mockMessageStore) SetNextTargetMsgSeqNum(next int) error { return nil } -func (m *mockMessageStore) CreationTime() time.Time { return time.Now() } -func (m *mockMessageStore) SaveMessage(seqNum int, msg []byte) error { return nil } -func (m *mockMessageStore) GetMessages(beginSeqNum, endSeqNum int) ([][]byte, error) { return nil, nil } -func (m *mockMessageStore) Refresh() error { return nil } -func (m *mockMessageStore) Reset() error { return nil } -func (m *mockMessageStore) Close() error { return nil } -func (m *mockMessageStore) IncrNextSenderMsgSeqNum() error { return nil } -func (m *mockMessageStore) IncrNextTargetMsgSeqNum() error { return nil } -func (m *mockMessageStore) IterateMessages(int, int, func([]byte) error) error { return nil } -func (m *mockMessageStore) SaveMessageAndIncrNextSenderMsgSeqNum(seqNum int, msg []byte) error { +func (m *mockMessageStore) NextSenderMsgSeqNum() int { return 1 } +func (m *mockMessageStore) NextTargetMsgSeqNum() int { return 1 } +func (m *mockMessageStore) IncrSenderMsgSeqNum() error { return nil } +func (m *mockMessageStore) IncrTargetMsgSeqNum() error { return nil } +func (m *mockMessageStore) SetNextSenderMsgSeqNum(_ int) error { return nil } +func (m *mockMessageStore) SetNextTargetMsgSeqNum(_ int) error { return nil } +func (m *mockMessageStore) CreationTime() time.Time { return time.Now() } +func (m *mockMessageStore) SaveMessage(_ int, _ []byte) error { return nil } +func (m *mockMessageStore) GetMessages(_, _ int) ([][]byte, error) { return nil, nil } +func (m *mockMessageStore) Refresh() error { return nil } +func (m *mockMessageStore) Reset() error { return nil } +func (m *mockMessageStore) Close() error { return nil } +func (m *mockMessageStore) IncrNextSenderMsgSeqNum() error { return nil } +func (m *mockMessageStore) IncrNextTargetMsgSeqNum() error { return nil } +func (m *mockMessageStore) IterateMessages(int, int, func([]byte) error) error { return nil } +func (m *mockMessageStore) SaveMessageAndIncrNextSenderMsgSeqNum(_ int, _ []byte) error { return m.saveMessageAndIncrError } func (m *mockMessageStore) SetCreationTime(time.Time) {} @@ -132,7 +132,7 @@ func (m *mockLogFactory) Create() (Log, error) { }, nil } -func (m *mockLogFactory) CreateSessionLog(sessionID SessionID) (Log, error) { +func (m *mockLogFactory) CreateSessionLog(_ SessionID) (Log, error) { return &mockLog{ onEvent: m.onEvent, }, nil @@ -150,16 +150,16 @@ func (m *mockAddr) String() string { return m.address } type mockConn struct{} -func (m *mockConn) Read(b []byte) (n int, err error) { return 0, nil } -func (m *mockConn) Write(b []byte) (n int, err error) { return len(b), nil } +func (m *mockConn) Read(_ []byte) (n int, err error) { return 0, nil } +func (m *mockConn) Write(_ []byte) (n int, err error) { return 0, nil } func (m *mockConn) Close() error { return nil } func (m *mockConn) LocalAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:8080"} } func (m *mockConn) RemoteAddr() net.Addr { return &mockAddr{network: "tcp", address: "127.0.0.1:9090"} } -func (m *mockConn) SetDeadline(t time.Time) error { return nil } -func (m *mockConn) SetReadDeadline(t time.Time) error { return nil } -func (m *mockConn) SetWriteDeadline(t time.Time) error { return nil } +func (m *mockConn) SetDeadline(_ time.Time) error { return nil } +func (m *mockConn) SetReadDeadline(_ time.Time) error { return nil } +func (m *mockConn) SetWriteDeadline(_ time.Time) error { return nil } -func (m *mockDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { +func (m *mockDialer) DialContext(_ context.Context, _, _ string) (net.Conn, error) { return &mockConn{}, nil } @@ -167,11 +167,11 @@ type mockLog struct { onEvent func(string) } -func (m *mockLog) OnIncoming(s []byte) {} -func (m *mockLog) OnOutgoing(s []byte) {} +func (m *mockLog) OnIncoming(_ []byte) {} +func (m *mockLog) OnOutgoing(_ []byte) {} func (m *mockLog) OnEvent(s string) { if m.onEvent != nil { m.onEvent(s) } } -func (m *mockLog) OnEventf(format string, a ...interface{}) {} +func (m *mockLog) OnEventf(_ string, _ ...interface{}) {}