390 lines
11 KiB
Go
390 lines
11 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 (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
|
|
"quantex.com/qfixpt/quickfix/config"
|
|
)
|
|
|
|
func TestSettings_New(t *testing.T) {
|
|
s := NewSettings()
|
|
assert.NotNil(t, s)
|
|
|
|
globalSettings := s.GlobalSettings()
|
|
assert.NotNil(t, globalSettings)
|
|
|
|
sessionSettings := s.SessionSettings()
|
|
assert.NotNil(t, sessionSettings)
|
|
assert.Empty(t, sessionSettings)
|
|
}
|
|
|
|
type SettingsAddSessionSuite struct {
|
|
suite.Suite
|
|
settings *Settings
|
|
}
|
|
|
|
func TestSettingsAddSessionSuite(t *testing.T) {
|
|
suite.Run(t, new(SettingsAddSessionSuite))
|
|
}
|
|
|
|
func (s *SettingsAddSessionSuite) SetupTest() {
|
|
s.settings = NewSettings()
|
|
}
|
|
|
|
func (s *SettingsAddSessionSuite) TestBeginStringValidation() {
|
|
ss := NewSessionSettings()
|
|
ss.Set(config.SenderCompID, "CB")
|
|
ss.Set(config.TargetCompID, "SS")
|
|
|
|
_, err := s.settings.AddSession(ss)
|
|
s.NotNil(err)
|
|
|
|
ss.Set(config.BeginString, "NotAValidBeginString")
|
|
_, err = s.settings.AddSession(ss)
|
|
s.NotNil(err)
|
|
|
|
var cases = []string{
|
|
BeginStringFIX40,
|
|
BeginStringFIX41,
|
|
BeginStringFIX42,
|
|
BeginStringFIX43,
|
|
BeginStringFIX44,
|
|
BeginStringFIXT11,
|
|
}
|
|
|
|
for _, beginString := range cases {
|
|
ss.Set(config.BeginString, beginString)
|
|
sid, err := s.settings.AddSession(ss)
|
|
s.Nil(err)
|
|
s.Equal(sid, SessionID{BeginString: beginString, SenderCompID: "CB", TargetCompID: "SS"})
|
|
}
|
|
}
|
|
|
|
func (s *SettingsAddSessionSuite) TestGlobalOverlay() {
|
|
globalSettings := s.settings.GlobalSettings()
|
|
globalSettings.Set(config.BeginString, "FIX.4.0")
|
|
globalSettings.Set(config.SocketAcceptPort, "1000")
|
|
|
|
s1 := NewSessionSettings()
|
|
s1.Set(config.BeginString, "FIX.4.1")
|
|
s1.Set(config.SenderCompID, "CB")
|
|
s1.Set(config.TargetCompID, "SS")
|
|
|
|
s2 := NewSessionSettings()
|
|
s2.Set(config.ResetOnLogon, "Y")
|
|
s2.Set(config.SenderCompID, "CB")
|
|
s2.Set(config.TargetCompID, "SS")
|
|
|
|
sessionID1 := SessionID{BeginString: "FIX.4.1", SenderCompID: "CB", TargetCompID: "SS"}
|
|
sessionID2 := SessionID{BeginString: "FIX.4.0", SenderCompID: "CB", TargetCompID: "SS"}
|
|
|
|
var addCases = []struct {
|
|
settings *SessionSettings
|
|
expectedSessionID SessionID
|
|
}{
|
|
{s1, sessionID1},
|
|
{s2, sessionID2},
|
|
}
|
|
|
|
for _, tc := range addCases {
|
|
sid, err := s.settings.AddSession(tc.settings)
|
|
s.Nil(err)
|
|
s.Equal(sid, tc.expectedSessionID)
|
|
}
|
|
|
|
var cases = []struct {
|
|
sessionID SessionID
|
|
input string
|
|
expected string
|
|
}{
|
|
{sessionID1, config.BeginString, "FIX.4.1"},
|
|
{sessionID1, config.SocketAcceptPort, "1000"},
|
|
{sessionID2, config.BeginString, "FIX.4.0"},
|
|
{sessionID2, config.SocketAcceptPort, "1000"},
|
|
{sessionID2, config.ResetOnLogon, "Y"},
|
|
}
|
|
|
|
sessionSettings := s.settings.SessionSettings()
|
|
s.Len(sessionSettings, 2)
|
|
for _, tc := range cases {
|
|
settings := sessionSettings[tc.sessionID]
|
|
|
|
actual, err := settings.Setting(tc.input)
|
|
s.Nil(err)
|
|
s.Equal(actual, tc.expected)
|
|
}
|
|
}
|
|
|
|
func (s *SettingsAddSessionSuite) TestRejectDuplicate() {
|
|
s1 := NewSessionSettings()
|
|
s1.Set(config.BeginString, "FIX.4.1")
|
|
s1.Set(config.SenderCompID, "CB")
|
|
s1.Set(config.TargetCompID, "SS")
|
|
|
|
s2 := NewSessionSettings()
|
|
s2.Set(config.BeginString, "FIX.4.0")
|
|
s2.Set(config.SenderCompID, "CB")
|
|
s2.Set(config.TargetCompID, "SS")
|
|
|
|
_, err := s.settings.AddSession(s1)
|
|
s.Nil(err)
|
|
_, err = s.settings.AddSession(s2)
|
|
s.Nil(err)
|
|
|
|
s3 := NewSessionSettings()
|
|
s1.Set(config.BeginString, "FIX.4.0")
|
|
s3.Set(config.SenderCompID, "CB")
|
|
s3.Set(config.TargetCompID, "SS")
|
|
_, err = s.settings.AddSession(s3)
|
|
s.NotNil(err, "Expected error for adding duplicate session")
|
|
|
|
sessionSettings := s.settings.SessionSettings()
|
|
s.Len(sessionSettings, 2)
|
|
}
|
|
|
|
func TestSettings_ParseSettings(t *testing.T) {
|
|
cfg := `
|
|
# default settings for sessions
|
|
[DEFAULT]
|
|
ConnectionType=initiator
|
|
ReconnectInterval=60
|
|
SenderCompID=TW
|
|
|
|
|
|
# session definition
|
|
[SESSION]
|
|
# inherit ConnectionType, ReconnectInterval and SenderCompID from default
|
|
|
|
BeginString=FIX.4.1
|
|
TargetCompID=ARCA
|
|
StartTime=12:30:00
|
|
EndTime=23:30:00
|
|
HeartBtInt=20
|
|
SocketConnectPort=9823
|
|
SocketConnectHost=123.123.123.123
|
|
DataDictionary=somewhere/FIX41.xml
|
|
|
|
|
|
[SESSION]
|
|
BeginString=FIX.4.0
|
|
TargetCompID=ISLD
|
|
StartTime=12:00:00
|
|
EndTime=23:00:00
|
|
HeartBtInt=30
|
|
SocketConnectPort=8323
|
|
SocketConnectHost=23.23.23.23
|
|
DataDictionary=somewhere/FIX40.xml
|
|
|
|
|
|
[SESSION]
|
|
BeginString=FIX.4.2
|
|
SenderSubID=TWSub
|
|
SenderLocationID=TWLoc
|
|
TargetCompID=INCA
|
|
TargetSubID=INCASub
|
|
TargetLocationID=INCALoc
|
|
StartTime=12:30:00
|
|
EndTime=21:30:00
|
|
# overide default setting for RecconnectInterval
|
|
ReconnectInterval=30
|
|
HeartBtInt=30
|
|
SocketConnectPort=6523
|
|
SocketConnectHost=3.3.3.3
|
|
# (optional) alternate connection ports and hosts to cycle through on failover
|
|
SocketConnectPort1=8392
|
|
SocketConnectHost1=8.8.8.8
|
|
SocketConnectPort2=2932
|
|
SocketConnectHost2=12.12.12.12
|
|
DataDictionary=somewhere/FIX42.xml
|
|
`
|
|
|
|
stringReader := strings.NewReader(cfg)
|
|
s, err := ParseSettings(stringReader)
|
|
assert.Nil(t, err)
|
|
assert.NotNil(t, s)
|
|
|
|
var globalTCs = []struct {
|
|
setting string
|
|
expected string
|
|
}{
|
|
{"ConnectionType", "initiator"},
|
|
{"ReconnectInterval", "60"},
|
|
{"SenderCompID", "TW"},
|
|
}
|
|
|
|
globalSettings := s.GlobalSettings()
|
|
for _, tc := range globalTCs {
|
|
actual, err := globalSettings.Setting(tc.setting)
|
|
assert.Nil(t, err)
|
|
|
|
assert.Equal(t, tc.expected, actual)
|
|
}
|
|
|
|
sessionSettings := s.SessionSettings()
|
|
assert.Len(t, sessionSettings, 3)
|
|
|
|
sessionID1 := SessionID{BeginString: "FIX.4.1", SenderCompID: "TW", TargetCompID: "ARCA"}
|
|
sessionID2 := SessionID{BeginString: "FIX.4.0", SenderCompID: "TW", TargetCompID: "ISLD"}
|
|
sessionID3 := SessionID{
|
|
BeginString: "FIX.4.2",
|
|
SenderCompID: "TW", SenderSubID: "TWSub", SenderLocationID: "TWLoc",
|
|
TargetCompID: "INCA", TargetSubID: "INCASub", TargetLocationID: "INCALoc"}
|
|
|
|
var sessionTCs = []struct {
|
|
sessionID SessionID
|
|
setting string
|
|
expected string
|
|
}{
|
|
{sessionID1, "ConnectionType", "initiator"},
|
|
{sessionID1, "ReconnectInterval", "60"},
|
|
{sessionID1, "SenderCompID", "TW"},
|
|
{sessionID1, "BeginString", "FIX.4.1"},
|
|
{sessionID1, "TargetCompID", "ARCA"},
|
|
{sessionID1, "StartTime", "12:30:00"},
|
|
{sessionID1, "EndTime", "23:30:00"},
|
|
{sessionID1, "HeartBtInt", "20"},
|
|
{sessionID1, "SocketConnectPort", "9823"},
|
|
{sessionID1, "SocketConnectHost", "123.123.123.123"},
|
|
{sessionID1, "DataDictionary", "somewhere/FIX41.xml"},
|
|
|
|
{sessionID2, "ConnectionType", "initiator"},
|
|
{sessionID2, "ReconnectInterval", "60"},
|
|
{sessionID2, "SenderCompID", "TW"},
|
|
{sessionID2, "BeginString", "FIX.4.0"},
|
|
{sessionID2, "TargetCompID", "ISLD"},
|
|
{sessionID2, "StartTime", "12:00:00"},
|
|
{sessionID2, "EndTime", "23:00:00"},
|
|
{sessionID2, "HeartBtInt", "30"},
|
|
{sessionID2, "SocketConnectPort", "8323"},
|
|
{sessionID2, "SocketConnectHost", "23.23.23.23"},
|
|
{sessionID2, "DataDictionary", "somewhere/FIX40.xml"},
|
|
|
|
{sessionID3, "ConnectionType", "initiator"},
|
|
{sessionID3, "BeginString", "FIX.4.2"},
|
|
{sessionID3, "SenderCompID", "TW"},
|
|
{sessionID3, "TargetCompID", "INCA"},
|
|
{sessionID3, "StartTime", "12:30:00"},
|
|
{sessionID3, "EndTime", "21:30:00"},
|
|
{sessionID3, "ReconnectInterval", "30"},
|
|
{sessionID3, "HeartBtInt", "30"},
|
|
{sessionID3, "SocketConnectPort", "6523"},
|
|
{sessionID3, "SocketConnectHost", "3.3.3.3"},
|
|
{sessionID3, "SocketConnectPort1", "8392"},
|
|
{sessionID3, "SocketConnectHost1", "8.8.8.8"},
|
|
{sessionID3, "SocketConnectPort2", "2932"},
|
|
{sessionID3, "SocketConnectHost2", "12.12.12.12"},
|
|
{sessionID3, "DataDictionary", "somewhere/FIX42.xml"},
|
|
}
|
|
|
|
for _, tc := range sessionTCs {
|
|
settings, ok := sessionSettings[tc.sessionID]
|
|
require.True(t, ok, "No Session recalled for %v", tc.sessionID)
|
|
actual, err := settings.Setting(tc.setting)
|
|
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, tc.expected, actual)
|
|
}
|
|
}
|
|
|
|
func TestSettings_ParseSettings_WithEqualsSignInValue(t *testing.T) {
|
|
s, err := ParseSettings(strings.NewReader(`
|
|
[DEFAULT]
|
|
ConnectionType=initiator
|
|
SQLDriver=mysql
|
|
SQLDataSourceName=root:root@/quickfix?parseTime=true&loc=UTC
|
|
|
|
[SESSION]
|
|
BeginString=FIX.4.2
|
|
SenderCompID=SENDER
|
|
TargetCompID=TARGET`))
|
|
|
|
require.Nil(t, err)
|
|
require.NotNil(t, s)
|
|
|
|
sessionSettings := s.SessionSettings()[SessionID{BeginString: "FIX.4.2", SenderCompID: "SENDER", TargetCompID: "TARGET"}]
|
|
val, err := sessionSettings.Setting("SQLDataSourceName")
|
|
assert.Nil(t, err)
|
|
assert.Equal(t, `root:root@/quickfix?parseTime=true&loc=UTC`, val)
|
|
}
|
|
|
|
func TestSettings_SessionIDFromSessionSettings(t *testing.T) {
|
|
var testCases = []struct {
|
|
globalBeginString string
|
|
globalTargetCompID string
|
|
globalSenderCompID string
|
|
sessionBeginString string
|
|
sessionTargetCompID string
|
|
sessionSenderCompID string
|
|
sessionQualifier string
|
|
expectedSessionID SessionID
|
|
}{
|
|
{globalBeginString: "FIX.4.0", globalTargetCompID: "CB", globalSenderCompID: "SS",
|
|
expectedSessionID: SessionID{BeginString: "FIX.4.0", TargetCompID: "CB", SenderCompID: "SS"}},
|
|
|
|
{sessionBeginString: "FIX.4.1", sessionTargetCompID: "GE", sessionSenderCompID: "LE",
|
|
expectedSessionID: SessionID{BeginString: "FIX.4.1", TargetCompID: "GE", SenderCompID: "LE"}},
|
|
|
|
{globalBeginString: "FIX.4.2", globalTargetCompID: "CB", sessionTargetCompID: "GE", sessionSenderCompID: "LE", sessionQualifier: "J",
|
|
expectedSessionID: SessionID{BeginString: "FIX.4.2", TargetCompID: "GE", SenderCompID: "LE", Qualifier: "J"}},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
globalSettings := NewSessionSettings()
|
|
sessionSettings := NewSessionSettings()
|
|
|
|
if tc.globalBeginString != "" {
|
|
globalSettings.Set(config.BeginString, tc.globalBeginString)
|
|
}
|
|
|
|
if tc.sessionBeginString != "" {
|
|
sessionSettings.Set(config.BeginString, tc.sessionBeginString)
|
|
}
|
|
|
|
if tc.globalTargetCompID != "" {
|
|
globalSettings.Set(config.TargetCompID, tc.globalTargetCompID)
|
|
}
|
|
|
|
if tc.sessionTargetCompID != "" {
|
|
sessionSettings.Set(config.TargetCompID, tc.sessionTargetCompID)
|
|
}
|
|
|
|
if tc.globalSenderCompID != "" {
|
|
globalSettings.Set(config.SenderCompID, tc.globalSenderCompID)
|
|
}
|
|
|
|
if tc.sessionSenderCompID != "" {
|
|
sessionSettings.Set(config.SenderCompID, tc.sessionSenderCompID)
|
|
}
|
|
|
|
if len(tc.sessionQualifier) > 0 {
|
|
sessionSettings.Set(config.SessionQualifier, tc.sessionQualifier)
|
|
}
|
|
|
|
actualSessionID := sessionIDFromSessionSettings(globalSettings, sessionSettings)
|
|
|
|
if tc.expectedSessionID != actualSessionID {
|
|
t.Errorf("Expected %v, got %v", tc.expectedSessionID, actualSessionID)
|
|
}
|
|
}
|
|
}
|