1329 lines
37 KiB
Go
1329 lines
37 KiB
Go
// Copyright (c) quickfixengine.org All rights reserved.
|
|
//
|
|
// This file may be distributed under the terms of the quickfixengine.org
|
|
// license as defined by quickfixengine.org and appearing in the file
|
|
// LICENSE included in the packaging of this file.
|
|
//
|
|
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING
|
|
// THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// See http://www.quickfixengine.org/LICENSE for licensing information.
|
|
//
|
|
// Contact ask@quickfixengine.org if any conditions of this licensing
|
|
// are not clear to you.
|
|
|
|
package quickfix
|
|
|
|
import (
|
|
"bytes"
|
|
"testing"
|
|
"time"
|
|
|
|
"quantex.com/qfixdpl/quickfix/internal"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
func newFIXString(val string) *FIXString {
|
|
s := FIXString(val)
|
|
return &s
|
|
}
|
|
|
|
type SessionSuite struct {
|
|
SessionSuiteRig
|
|
}
|
|
|
|
func TestSessionSuite(t *testing.T) {
|
|
suite.Run(t, new(SessionSuite))
|
|
}
|
|
|
|
func (s *SessionSuite) SetupTest() {
|
|
s.Init()
|
|
s.Require().Nil(s.session.store.Reset())
|
|
s.session.State = latentState{}
|
|
}
|
|
|
|
func (s *SessionSuite) TestFillDefaultHeader() {
|
|
s.session.sessionID.BeginString = "FIX.4.2"
|
|
s.session.sessionID.TargetCompID = "TAR"
|
|
s.session.sessionID.SenderCompID = "SND"
|
|
|
|
msg := NewMessage()
|
|
s.session.fillDefaultHeader(msg, nil)
|
|
s.FieldEquals(tagBeginString, "FIX.4.2", msg.Header)
|
|
s.FieldEquals(tagTargetCompID, "TAR", msg.Header)
|
|
s.FieldEquals(tagSenderCompID, "SND", msg.Header)
|
|
s.False(msg.Header.Has(tagSenderSubID))
|
|
s.False(msg.Header.Has(tagSenderLocationID))
|
|
s.False(msg.Header.Has(tagTargetSubID))
|
|
s.False(msg.Header.Has(tagTargetLocationID))
|
|
|
|
s.session.sessionID.BeginString = "FIX.4.3"
|
|
s.session.sessionID.TargetCompID = "TAR"
|
|
s.session.sessionID.TargetSubID = "TARS"
|
|
s.session.sessionID.TargetLocationID = "TARL"
|
|
s.session.sessionID.SenderCompID = "SND"
|
|
s.session.sessionID.SenderSubID = "SNDS"
|
|
s.session.sessionID.SenderLocationID = "SNDL"
|
|
|
|
msg = NewMessage()
|
|
s.session.fillDefaultHeader(msg, nil)
|
|
s.FieldEquals(tagBeginString, "FIX.4.3", msg.Header)
|
|
s.FieldEquals(tagTargetCompID, "TAR", msg.Header)
|
|
s.FieldEquals(tagTargetSubID, "TARS", msg.Header)
|
|
s.FieldEquals(tagTargetLocationID, "TARL", msg.Header)
|
|
s.FieldEquals(tagSenderCompID, "SND", msg.Header)
|
|
s.FieldEquals(tagSenderSubID, "SNDS", msg.Header)
|
|
s.FieldEquals(tagSenderLocationID, "SNDL", msg.Header)
|
|
}
|
|
|
|
func (s *SessionSuite) TestInsertSendingTime() {
|
|
var tests = []struct {
|
|
BeginString string
|
|
Precision TimestampPrecision
|
|
ExpectedPrecision TimestampPrecision
|
|
}{
|
|
{BeginStringFIX40, Millis, Seconds}, // Config is ignored for fix < 4.2.
|
|
{BeginStringFIX41, Millis, Seconds},
|
|
|
|
{BeginStringFIX42, Millis, Millis},
|
|
{BeginStringFIX42, Micros, Micros},
|
|
{BeginStringFIX42, Nanos, Nanos},
|
|
|
|
{BeginStringFIX43, Nanos, Nanos},
|
|
{BeginStringFIX44, Nanos, Nanos},
|
|
{BeginStringFIXT11, Nanos, Nanos},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.session.sessionID.BeginString = test.BeginString
|
|
s.timestampPrecision = test.Precision
|
|
|
|
msg := NewMessage()
|
|
s.session.insertSendingTime(msg)
|
|
|
|
var f FIXUTCTimestamp
|
|
s.Nil(msg.Header.GetField(tagSendingTime, &f))
|
|
s.Equal(f.Precision, test.ExpectedPrecision)
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckCorrectCompID() {
|
|
s.session.sessionID.TargetCompID = "TAR"
|
|
s.session.sessionID.SenderCompID = "SND"
|
|
|
|
var testCases = []struct {
|
|
senderCompID *FIXString
|
|
targetCompID *FIXString
|
|
returnsError bool
|
|
rejectReason int
|
|
}{
|
|
{returnsError: true, rejectReason: rejectReasonRequiredTagMissing},
|
|
{senderCompID: newFIXString("TAR"),
|
|
returnsError: true,
|
|
rejectReason: rejectReasonRequiredTagMissing},
|
|
{senderCompID: newFIXString("TAR"),
|
|
targetCompID: newFIXString("JCD"),
|
|
returnsError: true,
|
|
rejectReason: rejectReasonCompIDProblem},
|
|
{senderCompID: newFIXString("JCD"),
|
|
targetCompID: newFIXString("SND"),
|
|
returnsError: true,
|
|
rejectReason: rejectReasonCompIDProblem},
|
|
{senderCompID: newFIXString("TAR"),
|
|
targetCompID: newFIXString("SND"),
|
|
returnsError: false},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
msg := NewMessage()
|
|
|
|
if tc.senderCompID != nil {
|
|
msg.Header.SetField(tagSenderCompID, tc.senderCompID)
|
|
}
|
|
|
|
if tc.targetCompID != nil {
|
|
msg.Header.SetField(tagTargetCompID, tc.targetCompID)
|
|
}
|
|
|
|
rej := s.session.checkCompID(msg)
|
|
|
|
if !tc.returnsError {
|
|
s.Require().Nil(rej)
|
|
continue
|
|
}
|
|
|
|
s.NotNil(rej)
|
|
s.Equal(tc.rejectReason, rej.RejectReason())
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckBeginString() {
|
|
msg := NewMessage()
|
|
|
|
msg.Header.SetField(tagBeginString, FIXString("FIX.4.4"))
|
|
err := s.session.checkBeginString(msg)
|
|
s.Require().NotNil(err, "wrong begin string should return error")
|
|
s.IsType(incorrectBeginString{}, err)
|
|
|
|
msg.Header.SetField(tagBeginString, FIXString(s.session.sessionID.BeginString))
|
|
s.Nil(s.session.checkBeginString(msg))
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckTargetTooHigh() {
|
|
msg := NewMessage()
|
|
s.Require().Nil(s.session.store.SetNextTargetMsgSeqNum(45))
|
|
|
|
err := s.session.checkTargetTooHigh(msg)
|
|
s.Require().NotNil(err, "missing sequence number should return error")
|
|
s.Equal(rejectReasonRequiredTagMissing, err.RejectReason())
|
|
|
|
msg.Header.SetField(tagMsgSeqNum, FIXInt(47))
|
|
err = s.session.checkTargetTooHigh(msg)
|
|
s.Require().NotNil(err, "sequence number too high should return an error")
|
|
s.IsType(targetTooHigh{}, err)
|
|
|
|
// Spot on.
|
|
msg.Header.SetField(tagMsgSeqNum, FIXInt(45))
|
|
s.Nil(s.session.checkTargetTooHigh(msg))
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckSendingTime() {
|
|
s.session.MaxLatency = time.Duration(120) * time.Second
|
|
msg := NewMessage()
|
|
|
|
err := s.session.checkSendingTime(msg)
|
|
s.Require().NotNil(err, "sending time is a required field")
|
|
s.Equal(rejectReasonRequiredTagMissing, err.RejectReason())
|
|
|
|
sendingTime := time.Now().Add(time.Duration(-200) * time.Second)
|
|
msg.Header.SetField(tagSendingTime, FIXUTCTimestamp{Time: sendingTime})
|
|
|
|
err = s.session.checkSendingTime(msg)
|
|
s.Require().NotNil(err, "sending time too late should give error")
|
|
s.Equal(rejectReasonSendingTimeAccuracyProblem, err.RejectReason())
|
|
|
|
sendingTime = time.Now().Add(time.Duration(200) * time.Second)
|
|
msg.Header.SetField(tagSendingTime, FIXUTCTimestamp{Time: sendingTime})
|
|
|
|
err = s.session.checkSendingTime(msg)
|
|
s.Require().NotNil(err, "future sending time should give error")
|
|
s.Equal(rejectReasonSendingTimeAccuracyProblem, err.RejectReason())
|
|
|
|
sendingTime = time.Now()
|
|
msg.Header.SetField(tagSendingTime, FIXUTCTimestamp{Time: sendingTime})
|
|
|
|
s.Nil(s.session.checkSendingTime(msg), "sending time should be ok")
|
|
|
|
s.session.SkipCheckLatency = true
|
|
sendingTime = time.Now().Add(time.Duration(-200) * time.Second)
|
|
msg.Header.SetField(tagSendingTime, FIXUTCTimestamp{Time: sendingTime})
|
|
err = s.session.checkSendingTime(msg)
|
|
s.Require().Nil(err, "should skip latency check")
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckTargetTooLow() {
|
|
msg := NewMessage()
|
|
s.Require().Nil(s.session.store.SetNextTargetMsgSeqNum(45))
|
|
|
|
err := s.session.checkTargetTooLow(msg)
|
|
s.Require().NotNil(err, "sequence number is required")
|
|
s.Equal(rejectReasonRequiredTagMissing, err.RejectReason())
|
|
|
|
// Too low.
|
|
msg.Header.SetField(tagMsgSeqNum, FIXInt(43))
|
|
err = s.session.checkTargetTooLow(msg)
|
|
s.NotNil(err, "sequence number too low should return error")
|
|
s.IsType(targetTooLow{}, err)
|
|
|
|
// Spot on.
|
|
msg.Header.SetField(tagMsgSeqNum, FIXInt(45))
|
|
s.Nil(s.session.checkTargetTooLow(msg))
|
|
}
|
|
|
|
func (s *SessionSuite) TestShouldSendReset() {
|
|
var tests = []struct {
|
|
BeginString string
|
|
ResetOnLogon bool
|
|
ResetOnDisconnect bool
|
|
ResetOnLogout bool
|
|
NextSenderMsgSeqNum int
|
|
NextTargetMsgSeqNum int
|
|
Expected bool
|
|
}{
|
|
{BeginStringFIX40, true, false, false, 1, 1, false}, // ResetSeqNumFlag not available < fix41.
|
|
|
|
{BeginStringFIX41, true, false, false, 1, 1, true}, // Session must be configured to reset on logon.
|
|
{BeginStringFIX42, true, false, false, 1, 1, true},
|
|
{BeginStringFIX43, true, false, false, 1, 1, true},
|
|
{BeginStringFIX44, true, false, false, 1, 1, true},
|
|
{BeginStringFIXT11, true, false, false, 1, 1, true},
|
|
|
|
{BeginStringFIX41, false, true, false, 1, 1, true}, // Or disconnect.
|
|
{BeginStringFIX42, false, true, false, 1, 1, true},
|
|
{BeginStringFIX43, false, true, false, 1, 1, true},
|
|
{BeginStringFIX44, false, true, false, 1, 1, true},
|
|
{BeginStringFIXT11, false, true, false, 1, 1, true},
|
|
|
|
{BeginStringFIX41, false, false, true, 1, 1, true}, // Or logout.
|
|
{BeginStringFIX42, false, false, true, 1, 1, true},
|
|
{BeginStringFIX43, false, false, true, 1, 1, true},
|
|
{BeginStringFIX44, false, false, true, 1, 1, true},
|
|
{BeginStringFIXT11, false, false, true, 1, 1, true},
|
|
|
|
{BeginStringFIX41, true, true, false, 1, 1, true}, // Or combo.
|
|
{BeginStringFIX42, false, true, true, 1, 1, true},
|
|
{BeginStringFIX43, true, false, true, 1, 1, true},
|
|
{BeginStringFIX44, true, true, true, 1, 1, true},
|
|
|
|
{BeginStringFIX41, false, false, false, 1, 1, false}, // Or will not be set.
|
|
|
|
{BeginStringFIX41, true, false, false, 1, 10, false}, // Session seq numbers should be reset at the time of check.
|
|
{BeginStringFIX42, true, false, false, 2, 1, false},
|
|
{BeginStringFIX43, true, false, false, 14, 100, false},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.session.sessionID.BeginString = test.BeginString
|
|
s.session.ResetOnLogon = test.ResetOnLogon
|
|
s.session.ResetOnDisconnect = test.ResetOnDisconnect
|
|
s.session.ResetOnLogout = test.ResetOnLogout
|
|
|
|
s.Require().Nil(s.MockStore.SetNextSenderMsgSeqNum(test.NextSenderMsgSeqNum))
|
|
s.Require().Nil(s.MockStore.SetNextTargetMsgSeqNum(test.NextTargetMsgSeqNum))
|
|
|
|
s.Equal(s.shouldSendReset(), test.Expected)
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckSessionTimeNoStartTimeEndTime() {
|
|
var tests = []struct {
|
|
before, after sessionState
|
|
}{
|
|
{before: latentState{}},
|
|
{before: logonState{}},
|
|
{before: logoutState{}},
|
|
{before: inSession{}},
|
|
{before: resendState{}},
|
|
{before: pendingTimeout{resendState{}}},
|
|
{before: pendingTimeout{inSession{}}},
|
|
{before: notSessionTime{}, after: latentState{}},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.SetupTest()
|
|
s.session.SessionTime = nil
|
|
s.session.State = test.before
|
|
|
|
s.session.CheckSessionTime(s.session, time.Now())
|
|
if test.after != nil {
|
|
s.State(test.after)
|
|
} else {
|
|
s.State(test.before)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckSessionTimeInRange() {
|
|
var tests = []struct {
|
|
before, after sessionState
|
|
expectReset bool
|
|
}{
|
|
{before: latentState{}},
|
|
{before: logonState{}},
|
|
{before: logoutState{}},
|
|
{before: inSession{}},
|
|
{before: resendState{}},
|
|
{before: pendingTimeout{resendState{}}},
|
|
{before: pendingTimeout{inSession{}}},
|
|
{before: notSessionTime{}, after: latentState{}, expectReset: true},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.SetupTest()
|
|
s.session.State = test.before
|
|
|
|
now := time.Now().UTC()
|
|
memStore, memErr := NewMemoryStoreFactory().Create(s.sessionID)
|
|
s.Require().Nil(memErr)
|
|
|
|
if test.before.IsSessionTime() {
|
|
s.Require().Nil(memStore.Reset())
|
|
} else {
|
|
memStore.SetCreationTime(now.Add(time.Duration(-1) * time.Minute))
|
|
}
|
|
s.session.store = memStore
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
sessionTime, err := internal.NewUTCTimeRange(
|
|
internal.NewTimeOfDay(now.Clock()),
|
|
internal.NewTimeOfDay(now.Add(time.Hour).Clock()),
|
|
[]time.Weekday{},
|
|
)
|
|
s.Nil(err)
|
|
|
|
s.session.SessionTime = sessionTime
|
|
|
|
s.session.CheckSessionTime(s.session, now)
|
|
if test.after != nil {
|
|
s.State(test.after)
|
|
} else {
|
|
s.State(test.before)
|
|
}
|
|
|
|
if test.expectReset {
|
|
s.ExpectStoreReset()
|
|
} else {
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextSenderMsgSeqNum(2)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckSessionTimeNotInRange() {
|
|
var tests = []struct {
|
|
before sessionState
|
|
initiateLogon bool
|
|
expectOnLogout bool
|
|
expectSendLogout bool
|
|
}{
|
|
{before: latentState{}},
|
|
{before: logonState{}},
|
|
{before: logonState{}, initiateLogon: true, expectOnLogout: true},
|
|
{before: logoutState{}, expectOnLogout: true},
|
|
{before: inSession{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: resendState{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{resendState{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{inSession{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: notSessionTime{}},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.SetupTest()
|
|
s.session.State = test.before
|
|
s.session.InitiateLogon = test.initiateLogon
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
now := time.Now().UTC()
|
|
sessionTime, err := internal.NewUTCTimeRange(
|
|
internal.NewTimeOfDay(now.Add(time.Hour).Clock()),
|
|
internal.NewTimeOfDay(now.Add(time.Duration(2)*time.Hour).Clock()),
|
|
[]time.Weekday{},
|
|
)
|
|
s.Nil(err)
|
|
|
|
s.session.SessionTime = sessionTime
|
|
|
|
if test.expectOnLogout {
|
|
s.MockApp.On("OnLogout")
|
|
}
|
|
if test.expectSendLogout {
|
|
s.MockApp.On("ToAdmin")
|
|
}
|
|
s.session.CheckSessionTime(s.session, now)
|
|
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.State(notSessionTime{})
|
|
|
|
s.NextTargetMsgSeqNum(2)
|
|
if test.expectSendLogout {
|
|
s.LastToAdminMessageSent()
|
|
s.MessageType(string(msgTypeLogout), s.MockApp.lastToAdmin)
|
|
s.NextSenderMsgSeqNum(3)
|
|
} else {
|
|
s.NextSenderMsgSeqNum(2)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestCheckSessionTimeInRangeButNotSameRangeAsStore() {
|
|
var tests = []struct {
|
|
before sessionState
|
|
initiateLogon bool
|
|
expectOnLogout bool
|
|
expectSendLogout bool
|
|
}{
|
|
{before: latentState{}},
|
|
{before: logonState{}},
|
|
{before: logonState{}, initiateLogon: true, expectOnLogout: true},
|
|
{before: logoutState{}, expectOnLogout: true},
|
|
{before: inSession{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: resendState{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{resendState{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{inSession{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: notSessionTime{}},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.SetupTest()
|
|
s.session.State = test.before
|
|
s.session.InitiateLogon = test.initiateLogon
|
|
s.Require().Nil(s.store.Reset())
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
now := time.Now().UTC()
|
|
sessionTime, err := internal.NewUTCTimeRange(
|
|
internal.NewTimeOfDay(now.Add(time.Duration(-1)*time.Hour).Clock()),
|
|
internal.NewTimeOfDay(now.Add(time.Hour).Clock()),
|
|
[]time.Weekday{},
|
|
)
|
|
s.Nil(err)
|
|
|
|
s.session.SessionTime = sessionTime
|
|
|
|
if test.expectOnLogout {
|
|
s.MockApp.On("OnLogout")
|
|
}
|
|
if test.expectSendLogout {
|
|
s.MockApp.On("ToAdmin")
|
|
}
|
|
s.session.CheckSessionTime(s.session, now.AddDate(0, 0, 1))
|
|
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.State(latentState{})
|
|
if test.expectSendLogout {
|
|
s.LastToAdminMessageSent()
|
|
s.MessageType(string(msgTypeLogout), s.MockApp.lastToAdmin)
|
|
s.FieldEquals(tagMsgSeqNum, 2, s.MockApp.lastToAdmin.Header)
|
|
}
|
|
s.ExpectStoreReset()
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestIncomingNotInSessionTime() {
|
|
var tests = []struct {
|
|
before sessionState
|
|
initiateLogon bool
|
|
expectOnLogout bool
|
|
expectSendLogout bool
|
|
}{
|
|
{before: logonState{}},
|
|
{before: logonState{}, initiateLogon: true, expectOnLogout: true},
|
|
{before: logoutState{}, expectOnLogout: true},
|
|
{before: inSession{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: resendState{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{resendState{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{inSession{}}, expectOnLogout: true, expectSendLogout: true},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.SetupTest()
|
|
|
|
s.session.State = test.before
|
|
s.session.InitiateLogon = test.initiateLogon
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
now := time.Now().UTC()
|
|
sessionTime, err := internal.NewUTCTimeRange(
|
|
internal.NewTimeOfDay(now.Add(time.Hour).Clock()),
|
|
internal.NewTimeOfDay(now.Add(time.Duration(2)*time.Hour).Clock()),
|
|
[]time.Weekday{},
|
|
)
|
|
s.Nil(err)
|
|
|
|
s.session.SessionTime = sessionTime
|
|
if test.expectOnLogout {
|
|
s.MockApp.On("OnLogout")
|
|
}
|
|
if test.expectSendLogout {
|
|
s.MockApp.On("ToAdmin")
|
|
}
|
|
|
|
msg := s.NewOrderSingle()
|
|
msgBytes := msg.build()
|
|
|
|
s.session.Incoming(s.session, fixIn{bytes: bytes.NewBuffer(msgBytes)})
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.State(notSessionTime{})
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestSendAppMessagesNotInSessionTime() {
|
|
var tests = []struct {
|
|
before sessionState
|
|
initiateLogon bool
|
|
expectOnLogout bool
|
|
expectSendLogout bool
|
|
}{
|
|
{before: logonState{}},
|
|
{before: logonState{}, initiateLogon: true, expectOnLogout: true},
|
|
{before: logoutState{}, expectOnLogout: true},
|
|
{before: inSession{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: resendState{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{resendState{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{inSession{}}, expectOnLogout: true, expectSendLogout: true},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
s.SetupTest()
|
|
|
|
s.session.State = test.before
|
|
s.session.InitiateLogon = test.initiateLogon
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
s.MockApp.On("ToApp").Return(nil)
|
|
s.Require().Nil(s.queueForSend(s.NewOrderSingle()))
|
|
s.MockApp.AssertExpectations(s.T())
|
|
|
|
now := time.Now().UTC()
|
|
sessionTime, err := internal.NewUTCTimeRange(
|
|
internal.NewTimeOfDay(now.Add(time.Hour).Clock()),
|
|
internal.NewTimeOfDay(now.Add(time.Duration(2)*time.Hour).Clock()),
|
|
[]time.Weekday{},
|
|
)
|
|
s.Nil(err)
|
|
|
|
s.session.SessionTime = sessionTime
|
|
if test.expectOnLogout {
|
|
s.MockApp.On("OnLogout")
|
|
}
|
|
if test.expectSendLogout {
|
|
s.MockApp.On("ToAdmin")
|
|
}
|
|
|
|
s.session.SendAppMessages(s.session)
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.State(notSessionTime{})
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestTimeoutNotInSessionTime() {
|
|
var tests = []struct {
|
|
before sessionState
|
|
initiateLogon bool
|
|
expectOnLogout bool
|
|
expectSendLogout bool
|
|
}{
|
|
{before: logonState{}},
|
|
{before: logonState{}, initiateLogon: true, expectOnLogout: true},
|
|
{before: logoutState{}, expectOnLogout: true},
|
|
{before: inSession{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: resendState{}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{resendState{}}, expectOnLogout: true, expectSendLogout: true},
|
|
{before: pendingTimeout{inSession{}}, expectOnLogout: true, expectSendLogout: true},
|
|
}
|
|
|
|
var events = []internal.Event{internal.PeerTimeout, internal.NeedHeartbeat, internal.LogonTimeout, internal.LogoutTimeout}
|
|
|
|
for _, test := range tests {
|
|
for _, event := range events {
|
|
s.SetupTest()
|
|
|
|
s.session.State = test.before
|
|
s.session.InitiateLogon = test.initiateLogon
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
now := time.Now().UTC()
|
|
sessionTime, err := internal.NewUTCTimeRange(
|
|
internal.NewTimeOfDay(now.Add(time.Hour).Clock()),
|
|
internal.NewTimeOfDay(now.Add(time.Duration(2)*time.Hour).Clock()),
|
|
[]time.Weekday{},
|
|
)
|
|
s.Nil(err)
|
|
|
|
s.session.SessionTime = sessionTime
|
|
if test.expectOnLogout {
|
|
s.MockApp.On("OnLogout")
|
|
}
|
|
if test.expectSendLogout {
|
|
s.MockApp.On("ToAdmin")
|
|
}
|
|
|
|
s.session.Timeout(s.session, event)
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.State(notSessionTime{})
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestOnAdminConnectInitiateLogon() {
|
|
adminMsg := connect{
|
|
messageOut: s.Receiver.sendChannel,
|
|
}
|
|
s.session.State = latentState{}
|
|
s.session.HeartBtInt = time.Duration(45) * time.Second
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.session.InitiateLogon = true
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.onAdmin(adminMsg)
|
|
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.True(s.session.InitiateLogon)
|
|
s.False(s.sentReset)
|
|
s.State(logonState{})
|
|
s.LastToAdminMessageSent()
|
|
s.MessageType(string(msgTypeLogon), s.MockApp.lastToAdmin)
|
|
s.FieldEquals(tagHeartBtInt, 45, s.MockApp.lastToAdmin.Body)
|
|
s.FieldEquals(tagMsgSeqNum, 2, s.MockApp.lastToAdmin.Header)
|
|
s.NextSenderMsgSeqNum(3)
|
|
}
|
|
|
|
func (s *SessionSuite) TestInitiateLogonResetSeqNumFlag() {
|
|
adminMsg := connect{
|
|
messageOut: s.Receiver.sendChannel,
|
|
}
|
|
s.session.State = latentState{}
|
|
s.session.HeartBtInt = time.Duration(45) * time.Second
|
|
s.Require().Nil(s.store.Reset())
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.session.ResetOnLogon = true
|
|
s.session.InitiateLogon = true
|
|
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.onAdmin(adminMsg)
|
|
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.True(s.session.InitiateLogon)
|
|
s.True(s.sentReset)
|
|
s.State(logonState{})
|
|
s.LastToAdminMessageSent()
|
|
s.MessageType(string(msgTypeLogon), s.MockApp.lastToAdmin)
|
|
s.FieldEquals(tagMsgSeqNum, 1, s.MockApp.lastToAdmin.Header)
|
|
s.FieldEquals(tagResetSeqNumFlag, true, s.MockApp.lastToAdmin.Body)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(1)
|
|
}
|
|
|
|
func (s *SessionSuite) TestOnAdminConnectInitiateLogonFIXT11() {
|
|
s.session.sessionID.BeginString = string(BeginStringFIXT11)
|
|
s.session.DefaultApplVerID = "8"
|
|
s.session.InitiateLogon = true
|
|
|
|
adminMsg := connect{
|
|
messageOut: s.Receiver.sendChannel,
|
|
}
|
|
s.session.State = latentState{}
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.onAdmin(adminMsg)
|
|
|
|
s.MockApp.AssertExpectations(s.T())
|
|
s.True(s.session.InitiateLogon)
|
|
s.State(logonState{})
|
|
s.LastToAdminMessageSent()
|
|
s.MessageType(string(msgTypeLogon), s.MockApp.lastToAdmin)
|
|
s.FieldEquals(tagDefaultApplVerID, "8", s.MockApp.lastToAdmin.Body)
|
|
}
|
|
|
|
func (s *SessionSuite) TestOnAdminConnectRefreshOnLogon() {
|
|
var tests = []bool{true, false}
|
|
|
|
for _, doRefresh := range tests {
|
|
s.SetupTest()
|
|
s.session.RefreshOnLogon = doRefresh
|
|
|
|
adminMsg := connect{
|
|
messageOut: s.Receiver.sendChannel,
|
|
}
|
|
s.session.State = latentState{}
|
|
s.session.InitiateLogon = true
|
|
|
|
if doRefresh {
|
|
s.MockStore.On("Refresh").Return(nil)
|
|
}
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.onAdmin(adminMsg)
|
|
|
|
s.MockStore.AssertExpectations(s.T())
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestOnAdminConnectAccept() {
|
|
adminMsg := connect{
|
|
messageOut: s.Receiver.sendChannel,
|
|
}
|
|
s.session.State = latentState{}
|
|
s.IncrNextSenderMsgSeqNum()
|
|
|
|
s.session.onAdmin(adminMsg)
|
|
s.False(s.session.InitiateLogon)
|
|
s.State(logonState{})
|
|
s.NoMessageSent()
|
|
s.NextSenderMsgSeqNum(2)
|
|
}
|
|
|
|
func (s *SessionSuite) TestOnAdminConnectNotInSession() {
|
|
var tests = []bool{true, false}
|
|
|
|
for _, doInitiateLogon := range tests {
|
|
s.SetupTest()
|
|
s.session.State = notSessionTime{}
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.session.InitiateLogon = doInitiateLogon
|
|
|
|
adminMsg := connect{
|
|
messageOut: s.Receiver.sendChannel,
|
|
}
|
|
|
|
s.session.onAdmin(adminMsg)
|
|
|
|
s.State(notSessionTime{})
|
|
s.NoMessageSent()
|
|
s.Disconnected()
|
|
s.NextSenderMsgSeqNum(2)
|
|
}
|
|
}
|
|
|
|
func (s *SessionSuite) TestOnAdminStop() {
|
|
s.session.State = logonState{}
|
|
|
|
s.session.onAdmin(stopReq{})
|
|
s.Disconnected()
|
|
s.Stopped()
|
|
}
|
|
|
|
func (s *SessionSuite) TestResetOnDisconnect() {
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
s.session.ResetOnDisconnect = false
|
|
s.session.onDisconnect()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.ResetOnDisconnect = true
|
|
s.session.onDisconnect()
|
|
s.ExpectStoreReset()
|
|
}
|
|
|
|
type SessionSendTestSuite struct {
|
|
SessionSuiteRig
|
|
}
|
|
|
|
func TestSessionSendTestSuite(t *testing.T) {
|
|
suite.Run(t, new(SessionSendTestSuite))
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) SetupTest() {
|
|
suite.Init()
|
|
suite.session.State = inSession{}
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestQueueForSendAppMessage() {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
require.Nil(suite.T(), suite.queueForSend(suite.NewOrderSingle()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NoMessageSent()
|
|
suite.MessagePersisted(suite.MockApp.lastToApp)
|
|
suite.FieldEquals(tagMsgSeqNum, 1, suite.MockApp.lastToApp.Header)
|
|
suite.NextSenderMsgSeqNum(2)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestQueueForSendDoNotSendAppMessage() {
|
|
suite.MockApp.On("ToApp").Return(ErrDoNotSend)
|
|
suite.Equal(ErrDoNotSend, suite.queueForSend(suite.NewOrderSingle()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NoMessagePersisted(1)
|
|
suite.NoMessageSent()
|
|
suite.NextSenderMsgSeqNum(1)
|
|
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.send(suite.Heartbeat()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.LastToAdminMessageSent()
|
|
suite.MessagePersisted(suite.MockApp.lastToAdmin)
|
|
suite.NextSenderMsgSeqNum(2)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestQueueForSendAdminMessage() {
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.queueForSend(suite.Heartbeat()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.MessagePersisted(suite.MockApp.lastToAdmin)
|
|
suite.NoMessageSent()
|
|
suite.NextSenderMsgSeqNum(2)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendAppMessage() {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
require.Nil(suite.T(), suite.send(suite.NewOrderSingle()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.MessagePersisted(suite.MockApp.lastToApp)
|
|
suite.LastToAppMessageSent()
|
|
suite.NextSenderMsgSeqNum(2)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendAppDoNotSendMessage() {
|
|
suite.MockApp.On("ToApp").Return(ErrDoNotSend)
|
|
suite.Equal(ErrDoNotSend, suite.send(suite.NewOrderSingle()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NextSenderMsgSeqNum(1)
|
|
suite.NoMessageSent()
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendAdminMessage() {
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.send(suite.Heartbeat()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
|
|
suite.LastToAdminMessageSent()
|
|
suite.MessagePersisted(suite.MockApp.lastToAdmin)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendFlushesQueue() {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.queueForSend(suite.NewOrderSingle()))
|
|
require.Nil(suite.T(), suite.queueForSend(suite.Heartbeat()))
|
|
|
|
order1 := suite.MockApp.lastToApp
|
|
heartbeat := suite.MockApp.lastToAdmin
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NoMessageSent()
|
|
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
require.Nil(suite.T(), suite.send(suite.NewOrderSingle()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
order2 := suite.MockApp.lastToApp
|
|
suite.MessageSentEquals(order1)
|
|
suite.MessageSentEquals(heartbeat)
|
|
suite.MessageSentEquals(order2)
|
|
suite.NoMessageSent()
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendNotLoggedOn() {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.queueForSend(suite.NewOrderSingle()))
|
|
require.Nil(suite.T(), suite.queueForSend(suite.Heartbeat()))
|
|
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NoMessageSent()
|
|
|
|
var tests = []sessionState{logoutState{}, latentState{}, logonState{}}
|
|
|
|
for _, test := range tests {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
suite.session.State = test
|
|
require.Nil(suite.T(), suite.send(suite.NewOrderSingle()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NoMessageSent()
|
|
}
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendEnableLastMsgSeqNumProcessed() {
|
|
suite.session.State = inSession{}
|
|
suite.session.EnableLastMsgSeqNumProcessed = true
|
|
|
|
suite.Require().Nil(suite.session.store.SetNextTargetMsgSeqNum(45))
|
|
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
require.Nil(suite.T(), suite.send(suite.NewOrderSingle()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.LastToAppMessageSent()
|
|
|
|
suite.FieldEquals(tagLastMsgSeqNumProcessed, 44, suite.MockApp.lastToApp.Header)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestSendDisableMessagePersist() {
|
|
suite.session.State = inSession{}
|
|
suite.session.DisableMessagePersist = true
|
|
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
require.Nil(suite.T(), suite.send(suite.NewOrderSingle()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.LastToAppMessageSent()
|
|
suite.NoMessagePersisted(1)
|
|
suite.NextSenderMsgSeqNum(2)
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestDropAndSendAdminMessage() {
|
|
suite.MockApp.On("ToAdmin")
|
|
suite.Require().Nil(suite.dropAndSend(suite.Heartbeat()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
|
|
suite.MessagePersisted(suite.MockApp.lastToAdmin)
|
|
suite.LastToAdminMessageSent()
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestDropAndSendDropsQueue() {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.queueForSend(suite.NewOrderSingle()))
|
|
require.Nil(suite.T(), suite.queueForSend(suite.Heartbeat()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
|
|
suite.NoMessageSent()
|
|
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.dropAndSend(suite.Logon()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
|
|
msg := suite.MockApp.lastToAdmin
|
|
suite.MessageType(string(msgTypeLogon), msg)
|
|
suite.FieldEquals(tagMsgSeqNum, 3, msg.Header)
|
|
|
|
// Only one message sent.
|
|
suite.LastToAdminMessageSent()
|
|
suite.NoMessageSent()
|
|
}
|
|
|
|
func (suite *SessionSendTestSuite) TestDropAndSendDropsQueueWithReset() {
|
|
suite.MockApp.On("ToApp").Return(nil)
|
|
suite.MockApp.On("ToAdmin")
|
|
require.Nil(suite.T(), suite.queueForSend(suite.NewOrderSingle()))
|
|
require.Nil(suite.T(), suite.queueForSend(suite.Heartbeat()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
suite.NoMessageSent()
|
|
|
|
suite.MockApp.On("ToAdmin")
|
|
suite.Require().Nil(suite.MockStore.Reset())
|
|
require.Nil(suite.T(), suite.dropAndSend(suite.Logon()))
|
|
suite.MockApp.AssertExpectations(suite.T())
|
|
msg := suite.MockApp.lastToAdmin
|
|
|
|
suite.MessageType(string(msgTypeLogon), msg)
|
|
suite.FieldEquals(tagMsgSeqNum, 1, msg.Header)
|
|
|
|
// Only one message sent.
|
|
suite.LastToAdminMessageSent()
|
|
suite.NoMessageSent()
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTime() {
|
|
s.MockApp.On("ToAdmin")
|
|
s.SetupTest()
|
|
|
|
now := time.Now().UTC()
|
|
s.session.ResetSeqTime = now
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.IncrNextTargetMsgSeqNum()
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
|
|
s.session.CheckResetTime(s.session, now)
|
|
|
|
s.NextSenderMsgSeqNum(3)
|
|
s.NextSenderMsgSeqNum(3)
|
|
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeDisconnected() {
|
|
s.session.State = logonState{}
|
|
s.session.ResetSeqTime = time.Now().UTC().Add(time.Second * 2)
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.onAdmin(stopReq{})
|
|
s.Disconnected()
|
|
s.Stopped()
|
|
|
|
// Wait for reset time to pass.
|
|
time.Sleep(time.Second * 3)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
// Disconnected so the seq numbers should not be reset.
|
|
s.session.CheckResetTime(s.session, time.Now().UTC())
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeAfterElapse() {
|
|
s.session.State = logonState{}
|
|
before := time.Now().UTC()
|
|
resetTime := time.Now().UTC().Add(time.Second * 2)
|
|
after := resetTime.Add(time.Second * 1)
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(1)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeNotAfterDisconnect() {
|
|
s.session.State = logonState{}
|
|
before := time.Now().UTC()
|
|
resetTime := before.Add(time.Second * 2)
|
|
after := resetTime.Add(time.Second * 1)
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.onAdmin(stopReq{})
|
|
s.Disconnected()
|
|
s.Stopped()
|
|
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeDisconnected_LocalTZ() {
|
|
s.session.State = logonState{}
|
|
tz, err := time.LoadLocation("America/Chicago")
|
|
if err != nil {
|
|
s.T().Fatal(err)
|
|
}
|
|
s.session.TimeZone = tz
|
|
s.session.ResetSeqTime = time.Now().In(tz).Add(time.Second * 2)
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.onAdmin(stopReq{})
|
|
s.Disconnected()
|
|
s.Stopped()
|
|
|
|
// Wait for reset time to pass.
|
|
time.Sleep(time.Second * 3)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
// Disconnected so the seq numbers should not be reset.
|
|
s.session.CheckResetTime(s.session, time.Now().UTC())
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeAfterElapse_LocalTZ() {
|
|
s.session.State = logonState{}
|
|
tz, err := time.LoadLocation("America/Chicago")
|
|
if err != nil {
|
|
s.T().Fatal(err)
|
|
}
|
|
s.session.TimeZone = tz
|
|
before := time.Now().In(tz)
|
|
resetTime := before.Add(time.Second * 2)
|
|
after := resetTime.Add(time.Second * 1)
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(1)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeNotAfterDisconnect_LocalTZ() {
|
|
s.session.State = logonState{}
|
|
tz, err := time.LoadLocation("America/Chicago")
|
|
if err != nil {
|
|
s.T().Fatal(err)
|
|
}
|
|
s.session.TimeZone = tz
|
|
before := time.Now().In(tz)
|
|
resetTime := before.Add(time.Second * 2)
|
|
after := resetTime.Add(time.Second * 1)
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.onAdmin(stopReq{})
|
|
s.Disconnected()
|
|
s.Stopped()
|
|
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeAfterElapse_MultipleDaysLater() {
|
|
s.session.State = logonState{}
|
|
|
|
// Example Dates:
|
|
// ResetTime = 2025-06-08 10:15:30
|
|
// Before = 2025-07-10 10:15:29
|
|
// After = 2025-07-10 10:15:32
|
|
resetTime := time.Now()
|
|
before := resetTime.AddDate(0, 1, 2).Add(time.Second * -1)
|
|
after := resetTime.AddDate(0, 1, 2).Add(time.Second * 2)
|
|
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(1)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimeAtExactTime() {
|
|
s.session.State = logonState{}
|
|
resetTime := time.Now()
|
|
before := resetTime.Add(time.Second * -1)
|
|
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
// We are before the reset time, so we should not reset the seq numbers
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
// We check the reset time exactly at the configured time, so we reset
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, resetTime)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(1)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTimePreviousCheck() {
|
|
s.session.State = logonState{}
|
|
resetTime := time.Now()
|
|
before := resetTime.Add(time.Second * -1)
|
|
after := resetTime.Add(time.Second * 1)
|
|
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
// We are before the reset time, so we should not reset the seq numbers
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
// We just checked the reset time at the configured time, so we do not reset the seq num for the next check
|
|
s.session.lastCheckedResetSeqTime = resetTime
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
}
|
|
|
|
func (s *SessionSuite) TestSeqNumResetTime_NanoSeconds() {
|
|
s.session.State = logonState{}
|
|
resetTime := time.Now()
|
|
// Nanoseconds are not used in the resetSeqTime, but are referenced in the comparison of before/after
|
|
before := resetTime.Add(time.Nanosecond * -1)
|
|
after := resetTime.Add(time.Nanosecond * 1)
|
|
|
|
s.session.ResetSeqTime = resetTime
|
|
s.session.EnableResetSeqTime = true
|
|
|
|
s.NextSenderMsgSeqNum(1)
|
|
s.NextTargetMsgSeqNum(1)
|
|
s.IncrNextTargetMsgSeqNum()
|
|
s.IncrNextSenderMsgSeqNum()
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.MockApp.On("ToAdmin")
|
|
s.session.CheckResetTime(s.session, before)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(2)
|
|
|
|
s.session.lastCheckedResetSeqTime = before
|
|
s.session.CheckResetTime(s.session, after)
|
|
s.NextSenderMsgSeqNum(2)
|
|
s.NextTargetMsgSeqNum(1)
|
|
}
|