mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
* Engine: Expose WebsocketRoutineManager Without exposing the manager users don't know when it's ready to use. * wsManager: Remove duplicate shutdown chan make The shutdown channel was already in setup. Consumers could reasonably expect it to not be replaced in between the two, and it's not really part of Start to assign it. * wsManager: Fix IsRunning true before flushed Consumers must be able to tell when it's safe to start new subscriptions. Before this fix any new subscriptions would get unsubbed as part of the flush during `websocketRoutine`. * WSM: Fix Stop/Start/Stop failing We previously removed the shutdown channel from Start to avoid duplicate allocation. However that will result in a closed channel after the first Stop So it's better to remove it from the setup. It's private anyway. * WSM: Export WebsocketRoutineManager type
341 lines
8.4 KiB
Go
341 lines
8.4 KiB
Go
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/thrasher-corp/gocryptotrader/config"
|
|
)
|
|
|
|
func TestLoadConfigWithSettings(t *testing.T) {
|
|
empty := ""
|
|
somePath := "somePath"
|
|
// Clean up after the tests
|
|
defer os.RemoveAll(somePath)
|
|
tests := []struct {
|
|
name string
|
|
flags []string
|
|
settings *Settings
|
|
want *string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "invalid file",
|
|
settings: &Settings{
|
|
ConfigFile: "nonExistent.json",
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "test file",
|
|
settings: &Settings{
|
|
ConfigFile: config.TestFile,
|
|
CoreSettings: CoreSettings{EnableDryRun: true},
|
|
},
|
|
want: &empty,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "data dir in settings overrides config data dir",
|
|
flags: []string{"datadir"},
|
|
settings: &Settings{
|
|
ConfigFile: config.TestFile,
|
|
DataDir: somePath,
|
|
CoreSettings: CoreSettings{EnableDryRun: true},
|
|
},
|
|
want: &somePath,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
// prepare the 'flags'
|
|
flagSet := make(map[string]bool)
|
|
for _, v := range tt.flags {
|
|
flagSet[v] = true
|
|
}
|
|
// Run the test
|
|
got, err := loadConfigWithSettings(tt.settings, flagSet)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("loadConfigWithSettings() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != nil || tt.want != nil {
|
|
if (got == nil && tt.want != nil) || (got != nil && tt.want == nil) {
|
|
t.Errorf("loadConfigWithSettings() = is nil %v, want nil %v", got == nil, tt.want == nil)
|
|
} else if got.DataDirectory != *tt.want {
|
|
t.Errorf("loadConfigWithSettings() = %v, want %v", got.DataDirectory, *tt.want)
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStartStopDoesNotCausePanic(t *testing.T) {
|
|
t.Parallel()
|
|
tempDir := t.TempDir()
|
|
botOne, err := NewFromSettings(&Settings{
|
|
ConfigFile: config.TestFile,
|
|
CoreSettings: CoreSettings{EnableDryRun: true},
|
|
DataDir: tempDir,
|
|
}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
botOne.Settings.EnableGRPCProxy = false
|
|
for i := range botOne.Config.Exchanges {
|
|
if botOne.Config.Exchanges[i].Name != testExchange {
|
|
// there is no need to load all exchanges for this test
|
|
botOne.Config.Exchanges[i].Enabled = false
|
|
}
|
|
}
|
|
if err = botOne.Start(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
botOne.Stop()
|
|
}
|
|
|
|
var enableExperimentalTest = false
|
|
|
|
func TestStartStopTwoDoesNotCausePanic(t *testing.T) {
|
|
t.Parallel()
|
|
if !enableExperimentalTest {
|
|
t.Skip("test is functional, however does not need to be included in go test runs")
|
|
}
|
|
tempDir := t.TempDir()
|
|
tempDir2 := t.TempDir()
|
|
botOne, err := NewFromSettings(&Settings{
|
|
ConfigFile: config.TestFile,
|
|
CoreSettings: CoreSettings{EnableDryRun: true},
|
|
DataDir: tempDir,
|
|
}, nil)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
botOne.Settings.EnableGRPCProxy = false
|
|
|
|
botTwo, err := NewFromSettings(&Settings{
|
|
ConfigFile: config.TestFile,
|
|
CoreSettings: CoreSettings{EnableDryRun: true},
|
|
DataDir: tempDir2,
|
|
}, nil)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
botTwo.Settings.EnableGRPCProxy = false
|
|
|
|
if err = botOne.Start(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
if err = botTwo.Start(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
botOne.Stop()
|
|
botTwo.Stop()
|
|
}
|
|
|
|
func TestGetExchangeByName(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := (*ExchangeManager)(nil).GetExchangeByName("tehehe")
|
|
if !errors.Is(err, ErrNilSubsystem) {
|
|
t.Errorf("received: %v expected: %v", err, ErrNilSubsystem)
|
|
}
|
|
|
|
em := NewExchangeManager()
|
|
exch, err := em.NewExchangeByName(testExchange)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
exch.SetDefaults()
|
|
exch.SetEnabled(true)
|
|
err = em.Add(exch)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
|
}
|
|
e := &Engine{ExchangeManager: em}
|
|
|
|
if !exch.IsEnabled() {
|
|
t.Errorf("TestGetExchangeByName: Unexpected result")
|
|
}
|
|
|
|
exch.SetEnabled(false)
|
|
bfx, err := e.GetExchangeByName(testExchange)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if bfx.IsEnabled() {
|
|
t.Errorf("TestGetExchangeByName: Unexpected result")
|
|
}
|
|
if exch.GetName() != testExchange {
|
|
t.Errorf("TestGetExchangeByName: Unexpected result")
|
|
}
|
|
|
|
_, err = e.GetExchangeByName("Asdasd")
|
|
if !errors.Is(err, ErrExchangeNotFound) {
|
|
t.Errorf("received: %v expected: %v", err, ErrExchangeNotFound)
|
|
}
|
|
}
|
|
|
|
func TestUnloadExchange(t *testing.T) {
|
|
t.Parallel()
|
|
em := NewExchangeManager()
|
|
exch, err := em.NewExchangeByName(testExchange)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received '%v' expected '%v'", err, nil)
|
|
}
|
|
exch.SetDefaults()
|
|
exch.SetEnabled(true)
|
|
err = em.Add(exch)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
|
}
|
|
e := &Engine{ExchangeManager: em,
|
|
Config: &config.Config{Exchanges: []config.Exchange{{Name: testExchange}}},
|
|
}
|
|
err = e.UnloadExchange("asdf")
|
|
if !errors.Is(err, config.ErrExchangeNotFound) {
|
|
t.Errorf("error '%v', expected '%v'", err, config.ErrExchangeNotFound)
|
|
}
|
|
|
|
err = e.UnloadExchange(testExchange)
|
|
if err != nil {
|
|
t.Errorf("TestUnloadExchange: Failed to get exchange. %s",
|
|
err)
|
|
}
|
|
|
|
err = e.UnloadExchange(testExchange)
|
|
if !errors.Is(err, ErrExchangeNotFound) {
|
|
t.Errorf("error '%v', expected '%v'", err, ErrExchangeNotFound)
|
|
}
|
|
}
|
|
|
|
func TestDryRunParamInteraction(t *testing.T) {
|
|
t.Parallel()
|
|
bot := &Engine{
|
|
ExchangeManager: NewExchangeManager(),
|
|
Settings: Settings{},
|
|
Config: &config.Config{
|
|
Exchanges: []config.Exchange{
|
|
{
|
|
Name: testExchange,
|
|
WebsocketTrafficTimeout: time.Second,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
if err := bot.LoadExchange(testExchange, nil); err != nil {
|
|
t.Error(err)
|
|
}
|
|
exchCfg, err := bot.Config.GetExchangeConfig(testExchange)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if exchCfg.Verbose {
|
|
t.Error("verbose should have been disabled")
|
|
}
|
|
if err = bot.UnloadExchange(testExchange); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// Now set dryrun mode to true,
|
|
// enable exchange verbose mode and verify that verbose mode
|
|
// will be set on Bitfinex
|
|
bot.Settings.EnableDryRun = true
|
|
bot.Settings.CheckParamInteraction = true
|
|
bot.Settings.EnableExchangeVerbose = true
|
|
if err = bot.LoadExchange(testExchange, nil); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
exchCfg, err = bot.Config.GetExchangeConfig(testExchange)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if !bot.Settings.EnableDryRun ||
|
|
!exchCfg.Verbose {
|
|
t.Error("dryrun should be true and verbose should be true")
|
|
}
|
|
}
|
|
|
|
func TestFlagSetWith(t *testing.T) {
|
|
var isRunning bool
|
|
flags := make(FlagSet)
|
|
// Flag not set default to config
|
|
flags.WithBool("NOT SET", &isRunning, true)
|
|
if !isRunning {
|
|
t.Fatalf("received: '%v' but expected: '%v'", isRunning, true)
|
|
}
|
|
flags.WithBool("NOT SET", &isRunning, false)
|
|
if isRunning {
|
|
t.Fatalf("received: '%v' but expected: '%v'", isRunning, false)
|
|
}
|
|
|
|
flags["IS SET"] = true
|
|
isRunning = true
|
|
// Flag set true which will override config
|
|
flags.WithBool("IS SET", &isRunning, true)
|
|
if !isRunning {
|
|
t.Fatalf("received: '%v' but expected: '%v'", isRunning, true)
|
|
}
|
|
flags.WithBool("IS SET", &isRunning, false)
|
|
if !isRunning {
|
|
t.Fatalf("received: '%v' but expected: '%v'", isRunning, true)
|
|
}
|
|
|
|
flags["IS SET"] = true
|
|
isRunning = false
|
|
// Flag set false which will override config
|
|
flags.WithBool("IS SET", &isRunning, true)
|
|
if isRunning {
|
|
t.Fatalf("received: '%v' but expected: '%v'", isRunning, false)
|
|
}
|
|
flags.WithBool("IS SET", &isRunning, false)
|
|
if isRunning {
|
|
t.Fatalf("received: '%v' but expected: '%v'", isRunning, false)
|
|
}
|
|
}
|
|
|
|
func TestRegisterWebsocketDataHandler(t *testing.T) {
|
|
t.Parallel()
|
|
var e *Engine
|
|
err := e.RegisterWebsocketDataHandler(nil, false)
|
|
if !errors.Is(err, errNilBot) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, errNilBot)
|
|
}
|
|
|
|
e = &Engine{WebsocketRoutineManager: &WebsocketRoutineManager{}}
|
|
err = e.RegisterWebsocketDataHandler(func(_ string, _ interface{}) error { return nil }, false)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
|
}
|
|
}
|
|
|
|
func TestSetDefaultWebsocketDataHandler(t *testing.T) {
|
|
t.Parallel()
|
|
var e *Engine
|
|
err := e.SetDefaultWebsocketDataHandler()
|
|
if !errors.Is(err, errNilBot) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, errNilBot)
|
|
}
|
|
|
|
e = &Engine{WebsocketRoutineManager: &WebsocketRoutineManager{}}
|
|
err = e.SetDefaultWebsocketDataHandler()
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
|
}
|
|
}
|
|
|
|
func TestSettingsPrint(t *testing.T) {
|
|
t.Parallel()
|
|
var s *Settings
|
|
s.PrintLoadedSettings()
|
|
|
|
s = &Settings{}
|
|
s.PrintLoadedSettings()
|
|
}
|