Files
gocryptotrader/engine/apiserver_test.go
Ryan O'Hara-Reid d23898e63a engine: Adds shutdown method to exchange manager and unload all exchanges when engine is stopped (#1112)
* engine: shutdown and unload exchange when engine is stopped

* linter: fixes

* engine/exchMan: add nil check

* engine/exchanges: add shutdown method to exchanges, rm len check lock not needed, expanded code coverage, address some nits

* exchMan: report all failed shutdowns across exchanges, implement timer and monitoring routines.

* exchMan: improve shutdown sequence and aloc.

* further improvement

* exchman: log from warn to error

* websockconnection: Suppress error return when closure is caused by library

* linter: fix

* fix racies

* add note on why not parallel tests

* glorious: nits

* spelling kween

* thrasher: nits

* engine: change print of setting using reflection, I keep forgetting to implement this so program around forgetfulness

* engine/exchange_management: remove wait group and just rely on intermediary lock

* glorious: nits

* Update common/common.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

* Update main.go

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>

---------

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
2023-04-05 13:07:35 +10:00

292 lines
7.5 KiB
Go

package engine
import (
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
"os"
"reflect"
"testing"
"github.com/thrasher-corp/gocryptotrader/config"
)
func TestSetupAPIServerManager(t *testing.T) {
t.Parallel()
_, err := setupAPIServerManager(nil, nil, nil, nil, nil, "")
if !errors.Is(err, errNilRemoteConfig) {
t.Errorf("error '%v', expected '%v'", err, errNilRemoteConfig)
}
_, err = setupAPIServerManager(&config.RemoteControlConfig{}, nil, nil, nil, nil, "")
if !errors.Is(err, errNilPProfConfig) {
t.Errorf("error '%v', expected '%v'", err, errNilPProfConfig)
}
_, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, nil, nil, nil, "")
if !errors.Is(err, errNilExchangeManager) {
t.Errorf("error '%v', expected '%v'", err, errNilExchangeManager)
}
_, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, nil, nil, "")
if !errors.Is(err, errNilBot) {
t.Errorf("error '%v', expected '%v'", err, errNilBot)
}
_, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, "")
if !errors.Is(err, errEmptyConfigPath) {
t.Errorf("error '%v', expected '%v'", err, errEmptyConfigPath)
}
wd, _ := os.Getwd()
_, err = setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
}
func TestStartRESTServer(t *testing.T) {
t.Parallel()
wd, _ := os.Getwd()
m, err := setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StartRESTServer()
if !errors.Is(err, errServerDisabled) {
t.Errorf("error '%v', expected '%v'", err, errServerDisabled)
}
m.remoteConfig.DeprecatedRPC.Enabled = true
err = m.StartRESTServer()
if err != nil {
t.Fatal(err)
}
}
func TestStartWebsocketServer(t *testing.T) {
t.Parallel()
wd, _ := os.Getwd()
m, err := setupAPIServerManager(&config.RemoteControlConfig{}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StartWebsocketServer()
if !errors.Is(err, errServerDisabled) {
t.Errorf("error '%v', expected '%v'", err, errServerDisabled)
}
m.remoteConfig.WebsocketRPC.Enabled = true
err = m.StartWebsocketServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
}
func TestStopRESTServer(t *testing.T) {
t.Parallel()
wd, _ := os.Getwd()
m, err := setupAPIServerManager(&config.RemoteControlConfig{
DeprecatedRPC: config.DepcrecatedRPCConfig{
Enabled: true,
ListenAddress: "localhost:9051",
},
}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StopRESTServer()
if !errors.Is(err, ErrSubSystemNotStarted) {
t.Errorf("error '%v', expected '%v'", err, ErrSubSystemNotStarted)
}
err = m.StartRESTServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StopRESTServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
// do it again to ensure things have reset appropriately and no errors occur starting
err = m.StartRESTServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StopRESTServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
}
func TestWebsocketStop(t *testing.T) {
t.Parallel()
wd, _ := os.Getwd()
m, err := setupAPIServerManager(&config.RemoteControlConfig{
WebsocketRPC: config.WebsocketRPCConfig{
Enabled: true,
ListenAddress: "localhost:9052",
},
}, &config.Profiler{}, &ExchangeManager{}, &fakeBot{}, nil, wd)
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StopWebsocketServer()
if !errors.Is(err, ErrSubSystemNotStarted) {
t.Errorf("error '%v', expected '%v'", err, ErrSubSystemNotStarted)
}
err = m.StartWebsocketServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StopWebsocketServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
// do it again to ensure things have reset appropriately and no errors occur starting
err = m.StartWebsocketServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
err = m.StopWebsocketServer()
if !errors.Is(err, nil) {
t.Errorf("error '%v', expected '%v'", err, nil)
}
}
func TestIsRESTServerRunning(t *testing.T) {
t.Parallel()
m := &apiServerManager{}
if m.IsRESTServerRunning() {
t.Error("expected false")
}
m.restStarted = 1
if !m.IsRESTServerRunning() {
t.Error("expected true")
}
m = nil
if m.IsRESTServerRunning() {
t.Error("expected false")
}
}
func TestIsWebsocketServerRunning(t *testing.T) {
t.Parallel()
m := &apiServerManager{}
if m.IsWebsocketServerRunning() {
t.Error("expected false")
}
m.websocketStarted = 1
if !m.IsWebsocketServerRunning() {
t.Error("expected true")
}
m = nil
if m.IsWebsocketServerRunning() {
t.Error("expected false")
}
}
func TestGetAllActiveOrderbooks(t *testing.T) {
man := NewExchangeManager()
bs, err := man.NewExchangeByName("Bitstamp")
if err != nil {
t.Fatal(err)
}
bs.SetDefaults()
err = man.Add(bs)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
resp := getAllActiveOrderbooks(man)
if resp == nil {
t.Error("expected not nil")
}
}
func TestGetAllActiveTickers(t *testing.T) {
t.Parallel()
man := NewExchangeManager()
bs, err := man.NewExchangeByName("Bitstamp")
if err != nil {
t.Fatal(err)
}
bs.SetDefaults()
err = man.Add(bs)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
resp := getAllActiveTickers(man)
if resp == nil {
t.Error("expected not nil")
}
}
func TestGetAllActiveAccounts(t *testing.T) {
t.Parallel()
man := NewExchangeManager()
bs, err := man.NewExchangeByName("Bitstamp")
if err != nil {
t.Fatal(err)
}
bs.SetDefaults()
err = man.Add(bs)
if !errors.Is(err, nil) {
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
}
resp := getAllActiveAccounts(man)
if resp == nil {
t.Error("expected not nil")
}
}
func makeHTTPGetRequest(t *testing.T, response interface{}) *http.Response {
t.Helper()
w := httptest.NewRecorder()
err := writeResponse(w, response)
if err != nil {
t.Error("Failed to make response.", err)
}
return w.Result()
}
// TestConfigAllJsonResponse test if config/all restful json response is valid
func TestConfigAllJsonResponse(t *testing.T) {
t.Parallel()
var c config.Config
err := c.LoadConfig(config.TestFile, true)
if err != nil {
t.Error(err)
}
resp := makeHTTPGetRequest(t, c)
body, err := io.ReadAll(resp.Body)
if err != nil {
t.Error("Body not readable", err)
}
err = resp.Body.Close()
if err != nil {
t.Error("Body not closable", err)
}
var responseConfig config.Config
jsonErr := json.Unmarshal(body, &responseConfig)
if jsonErr != nil {
t.Error("Response not parse-able as json", err)
}
if !reflect.DeepEqual(responseConfig, c) {
t.Error("Json not equal to config")
}
}
// fakeBot is a basic implementation of the iBot interface used for testing
type fakeBot struct{}
// SetupExchanges is a basic implementation of the iBot interface used for testing
func (f *fakeBot) SetupExchanges() error {
return nil
}