Files
gocryptotrader/exchanges/currencystate/currency_state_test.go
Ryan O'Hara-Reid 5dfbbf84de engine/exchanges: Add exchange currency state subsystem (#774)
* state: Add management system (init)

* linter: fix

* engine: gofmt

* gct: after merge fixup

* documentation: add

* rpc: implement services for testing

* gctcli: gofmt state_management.go

* documentation: reinstate lost information

* state: Add pair check to determine trading operation

* exchanges: add interface for specific state scoped subsystem functionality

* engine/order_man: reduce code footprint using new method

* RPC: implement pair trading request and change exported name to something specific to state

* engine: add tests

* engine: Add to withdraw manager

* documentation: reinstate soxipy in contrib. list

* engine: const fake name

* Glorious: NITERINOS

* merge: fix issues

* engine: csm incorporate service name into log output

* engine: fix linter issues

* gct: fix tests

* currencystate: remove management type

* rpc: fix tests

* backtester: fix tests

* Update engine/currency_state_manager.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update engine/currency_state_manager.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/currencystate/currency_state.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/alert/alert.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/alert/alert.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: nits

* config: integrate with config and remove flag delay adjustment

* gctcli: fix issues after name changes

* engine: gofmt manager file

* Update engine/rpcserver.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* engine: Add enable/disable manager functions, add default popoulation for potential assets

* linter: fix

* engine/test: bump subsystem count

* Update engine/currency_state_manager.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/bithumb/bithumb.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: nits addressed

* alert: fix commenting for its generalized purpose

* glorious: nits

* engine: use standard string in log output

* bitfinex: apply patch, thanks @thrasher-

* bitfinex: fix spelling

* engine/currencystate: Add logs/fix logs

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
2021-09-27 13:33:49 +10:00

325 lines
8.6 KiB
Go

package currencystate
import (
"errors"
"sync"
"testing"
"github.com/thrasher-corp/gocryptotrader/common/convert"
"github.com/thrasher-corp/gocryptotrader/currency"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
)
func TestNewCurrencyStates(t *testing.T) {
if NewCurrencyStates() == nil {
t.Fatal("unexpected value")
}
}
func TestGetSnapshot(t *testing.T) {
t.Parallel()
_, err := (*States)(nil).GetCurrencyStateSnapshot()
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
o, err := (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {currency.BTC.Item: {
withdrawals: true,
deposits: true,
trading: true,
}},
},
}).GetCurrencyStateSnapshot()
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
if o == nil {
t.Fatal("unexpected value")
}
}
func TestCanTradePair(t *testing.T) {
t.Parallel()
err := (*States)(nil).CanTradePair(currency.Pair{}, "")
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
err = (&States{}).CanTradePair(currency.Pair{}, "")
if !errors.Is(err, errEmptyCurrency) {
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
}
cp := currency.NewPair(currency.BTC, currency.USD)
err = (&States{}).CanTradePair(cp, "")
if !errors.Is(err, asset.ErrNotSupported) {
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
}
err = (&States{}).CanTradePair(cp, asset.Spot)
if !errors.Is(err, nil) { // not found but default to operational
t.Fatalf("received: %v, but expected: %v", err, nil)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {trading: true},
currency.USD.Item: {trading: true},
},
},
}).CanTradePair(cp, asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {trading: false},
currency.USD.Item: {trading: true},
},
},
}).CanTradePair(cp, asset.Spot)
if !errors.Is(err, errTradingNotAllowed) {
t.Fatalf("received: %v, but expected: %v", err, errTradingNotAllowed)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {trading: true},
currency.USD.Item: {trading: false},
},
},
}).CanTradePair(cp, asset.Spot)
if !errors.Is(err, errTradingNotAllowed) {
t.Fatalf("received: %v, but expected: %v", err, errTradingNotAllowed)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {trading: false},
currency.USD.Item: {trading: false},
},
},
}).CanTradePair(cp, asset.Spot)
if !errors.Is(err, errTradingNotAllowed) {
t.Fatalf("received: %v, but expected: %v", err, errTradingNotAllowed)
}
}
func TestStatesCanTrade(t *testing.T) {
t.Parallel()
err := (*States)(nil).CanTrade(currency.Code{}, "")
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
err = (&States{}).CanTrade(currency.Code{}, "")
if !errors.Is(err, errEmptyCurrency) {
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
}
}
func TestStatesCanWithdraw(t *testing.T) {
t.Parallel()
err := (*States)(nil).CanWithdraw(currency.Code{}, "")
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
err = (&States{}).CanWithdraw(currency.Code{}, "")
if !errors.Is(err, errEmptyCurrency) {
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {withdrawals: true},
},
},
}).CanWithdraw(currency.BTC, asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {},
},
},
}).CanWithdraw(currency.BTC, asset.Spot)
if !errors.Is(err, errWithdrawalsNotAllowed) {
t.Fatalf("received: %v, but expected: %v", err, errWithdrawalsNotAllowed)
}
}
func TestStatesCanDeposit(t *testing.T) {
t.Parallel()
err := (*States)(nil).CanDeposit(currency.Code{}, "")
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
err = (&States{}).CanDeposit(currency.Code{}, "")
if !errors.Is(err, errEmptyCurrency) {
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {deposits: true},
},
},
}).CanDeposit(currency.BTC, asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {
currency.BTC.Item: {},
},
},
}).CanDeposit(currency.BTC, asset.Spot)
if !errors.Is(err, errDepositNotAllowed) {
t.Fatalf("received: %v, but expected: %v", err, errDepositNotAllowed)
}
}
func TestStatesUpdateAll(t *testing.T) {
t.Parallel()
err := (*States)(nil).UpdateAll("", nil)
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
err = (&States{}).UpdateAll("", nil)
if !errors.Is(err, asset.ErrNotSupported) {
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
}
err = (&States{}).UpdateAll(asset.Spot, nil)
if !errors.Is(err, errUpdatesAreNil) {
t.Fatalf("received: %v, but expected: %v", err, errUpdatesAreNil)
}
s := &States{
m: map[asset.Item]map[*currency.Item]*Currency{},
}
err = s.UpdateAll(asset.Spot, map[currency.Code]Options{
currency.BTC: {
Withdraw: convert.BoolPtr(true),
Trade: convert.BoolPtr(true),
Deposit: convert.BoolPtr(true)},
})
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
err = s.UpdateAll(asset.Spot, map[currency.Code]Options{currency.BTC: {
Withdraw: convert.BoolPtr(false),
Deposit: convert.BoolPtr(false),
Trade: convert.BoolPtr(false),
}})
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
c, err := s.Get(currency.BTC, asset.Spot)
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
if c.CanDeposit() || c.CanTrade() || c.CanWithdraw() {
t.Fatal()
}
}
func TestStatesUpdate(t *testing.T) {
t.Parallel()
err := (*States)(nil).Update(currency.Code{}, "", Options{})
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
err = (&States{}).Update(currency.Code{}, "", Options{})
if !errors.Is(err, errEmptyCurrency) {
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
}
err = (&States{}).Update(currency.BTC, "", Options{})
if !errors.Is(err, asset.ErrNotSupported) {
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
}
err = (&States{
m: map[asset.Item]map[*currency.Item]*Currency{
asset.Spot: {currency.BTC.Item: &Currency{}},
},
}).Update(currency.BTC, asset.Spot, Options{})
if !errors.Is(err, nil) {
t.Fatalf("received: %v, but expected: %v", err, nil)
}
}
func TestStatesGet(t *testing.T) {
t.Parallel()
_, err := (*States)(nil).Get(currency.Code{}, "")
if !errors.Is(err, errNilStates) {
t.Fatalf("received: %v, but expected: %v", err, errNilStates)
}
_, err = (&States{}).Get(currency.Code{}, "")
if !errors.Is(err, errEmptyCurrency) {
t.Fatalf("received: %v, but expected: %v", err, errEmptyCurrency)
}
_, err = (&States{}).Get(currency.BTC, "")
if !errors.Is(err, asset.ErrNotSupported) {
t.Fatalf("received: %v, but expected: %v", err, asset.ErrNotSupported)
}
_, err = (&States{}).Get(currency.BTC, asset.Spot)
if !errors.Is(err, ErrCurrencyStateNotFound) {
t.Fatalf("received: %v, but expected: %v", err, ErrCurrencyStateNotFound)
}
}
func TestCurrencyGetState(t *testing.T) {
o := (&Currency{}).GetState()
if *o.Deposit || *o.Trade || *o.Withdraw {
t.Fatal("unexpected values")
}
}
func TestAlerting(t *testing.T) {
c := Currency{}
var start, finish sync.WaitGroup
start.Add(3)
finish.Add(3)
go waitForAlert(c.WaitTrading(nil), &start, &finish)
go waitForAlert(c.WaitDeposit(nil), &start, &finish)
go waitForAlert(c.WaitWithdraw(nil), &start, &finish)
start.Wait()
c.update(Options{
Trade: convert.BoolPtr(true),
Withdraw: convert.BoolPtr(true),
Deposit: convert.BoolPtr(true)})
finish.Wait()
}
func waitForAlert(ch <-chan bool, start, finish *sync.WaitGroup) {
defer finish.Done()
start.Done()
<-ch
}