mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-16 23:16:48 +00:00
* Websocket: Remove IsInit and simplify SetProxyAddress IsInit was basically the same as IsConnected. Any time Connect was called both would be set to true. Any time we had a disconnect they'd both be set to false Shutdown() incorrectly didn't setInit(false) SetProxyAddress simplified to only reconnect a connected Websocket. Any other state means it hasn't been Connected, or it's about to reconnect anyway. There's no handling for IsConnecting previously, either, so I've wrapped that behind the main mutex. * Websocket: Expand and Assertify tests * Websocket: Simplify state transistions * Websocket: Simplify Connecting/Connected state * Websocket: Tests and errors for websocket * Websocket: Make WebsocketNotEnabled a real error This allows for testing and avoids the repetition. If each returned error is a error.New() you can never use errors.Is() * Websocket: Add more testable errors * Websocket: Improve GenerateMessageID test Testing just the last id doesn't feel very robust * Websocket: Protect Setup() from races * Websocket: Use atomics instead of mutex This was spurred by looking at the setState call in trafficMonitor and the effect on blocking and efficiency. With the new atomic types in Go 1.19, and the small types in use here, atomics should be safe for our usage. bools should be truly atomic, and uint32 is atomic when the accepted value range is less than one byte/uint8 since that can be written atomicly by concurrent processors. Maybe that's not even a factor any more, however we don't even have to worry enough to check. * Websocket: Fix and simplify traffic monitor trafficMonitor had a check throttle at the end of the for loop to stop it just gobbling the (blocking) trafficAlert channel non-stop. That makes sense, except that nothing is sent to the trafficAlert channel if there's no listener. So that means that it's out by one second on the trafficAlert, because any traffic received during the pause is doesn't try to send a traffic alert. The unstopped timer is deliberately leaked for later GC when shutdown. It won't delay/block anything, and it's a trivial memory leak during an infrequent event. Deliberately Choosing to recreate the timer each time instead of using Stop, drain and reset * Websocket: Split traficMonitor test on behaviours * Websocket: Remove trafficMonitor connected status trafficMonitor does not need to set the connection to be connected. Connect() does that. Anything after that should result in a full shutdown and restart. It can't and shouldn't become connected unexpectedly, and this is most likely a race anyway. Also dropped trafficCheckInterval to 100ms to mitigate races of traffic alerts being buffered for too long. * Websocket: Set disconnected earlier in Shutdown This caused a possible race where state is still connected, but we start to trigger interested actors via ShutdownC and Wait. They may check state and then call Shutdown again, such as trafficMonitor * Websocket: Wait 5s for slow tests to pass traffic draining Keep getting failures upstream on test rigs. Think they can be very contended, so this pushes the boundary right out to 5s
2022 lines
67 KiB
Go
2022 lines
67 KiB
Go
package bitfinex
|
|
|
|
import (
|
|
"bufio"
|
|
"context"
|
|
"errors"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/buger/jsonparser"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/config"
|
|
"github.com/thrasher-corp/gocryptotrader/core"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/order"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/orderbook"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/stream"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/subscription"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/ticker"
|
|
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
|
|
)
|
|
|
|
// Please supply API keys here or in config/testdata.json to test authenticated endpoints
|
|
const (
|
|
apiKey = ""
|
|
apiSecret = ""
|
|
canManipulateRealOrders = false
|
|
)
|
|
|
|
var b = &Bitfinex{}
|
|
var wsConnected bool
|
|
var btcusdPair = currency.NewPair(currency.BTC, currency.USD)
|
|
|
|
func TestMain(m *testing.M) {
|
|
b.SetDefaults()
|
|
cfg := config.GetConfig()
|
|
err := cfg.LoadConfig("../../testdata/configtest.json", true)
|
|
if err != nil {
|
|
log.Fatal("Bitfinex load config error", err)
|
|
}
|
|
bfxConfig, err := cfg.GetExchangeConfig("Bitfinex")
|
|
if err != nil {
|
|
log.Fatal("Bitfinex Setup() init error")
|
|
}
|
|
b.Websocket = sharedtestvalues.NewTestWebsocket()
|
|
err = b.Setup(bfxConfig)
|
|
if err != nil {
|
|
log.Fatal("Bitfinex setup error", err)
|
|
}
|
|
if apiKey != "" {
|
|
b.SetCredentials(apiKey, apiSecret, "", "", "", "")
|
|
}
|
|
if !b.Enabled || len(b.BaseCurrencies) < 1 {
|
|
log.Fatal("Bitfinex Setup values not set correctly")
|
|
}
|
|
|
|
if sharedtestvalues.AreAPICredentialsSet(b) {
|
|
b.API.AuthenticatedSupport = true
|
|
b.API.AuthenticatedWebsocketSupport = true
|
|
}
|
|
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func TestGetV2MarginFunding(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetV2MarginFunding(context.Background(), "fUSD", "2", 2)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetV2MarginInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetV2MarginInfo(context.Background(), "base")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = b.GetV2MarginInfo(context.Background(), "tBTCUSD")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
_, err = b.GetV2MarginInfo(context.Background(), "sym_all")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountInfoV2(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetAccountInfoV2(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetV2FundingInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetV2FundingInfo(context.Background(), "fUST")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetV2Balances(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetV2Balances(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetDerivativeStatusInfo(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := b.GetDerivativeStatusInfo(context.Background(), "ALL", "", "", 0, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetPairs(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := b.GetPairs(context.Background(), asset.Binary)
|
|
if !errors.Is(err, asset.ErrNotSupported) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, asset.ErrNotSupported)
|
|
}
|
|
|
|
assets := b.GetAssetTypes(false)
|
|
for x := range assets {
|
|
_, err := b.GetPairs(context.Background(), assets[x])
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUpdateTradablePairs(t *testing.T) {
|
|
t.Parallel()
|
|
updatePairsOnce(t)
|
|
}
|
|
|
|
var updatePairsGuard sync.Once
|
|
|
|
func updatePairsOnce(tb testing.TB) {
|
|
tb.Helper()
|
|
updatePairsGuard.Do(func() {
|
|
err := b.UpdateTradablePairs(context.Background(), true)
|
|
assert.NoError(tb, err, "UpdateTradablePairs should not error")
|
|
})
|
|
}
|
|
|
|
func TestUpdateOrderExecutionLimits(t *testing.T) {
|
|
t.Parallel()
|
|
tests := map[asset.Item][]currency.Pair{
|
|
asset.Spot: {
|
|
currency.NewPair(currency.ETH, currency.UST),
|
|
currency.NewPair(currency.BTC, currency.UST),
|
|
},
|
|
}
|
|
for assetItem, pairs := range tests {
|
|
if err := b.UpdateOrderExecutionLimits(context.Background(), assetItem); err != nil {
|
|
t.Errorf("Error fetching %s pairs for test: %v", assetItem, err)
|
|
continue
|
|
}
|
|
for _, pair := range pairs {
|
|
limits, err := b.GetOrderExecutionLimits(assetItem, pair)
|
|
if err != nil {
|
|
t.Errorf("GetOrderExecutionLimits() error during TestExecutionLimits; Asset: %s Pair: %s Err: %v", assetItem, pair, err)
|
|
continue
|
|
}
|
|
if limits.MinimumBaseAmount == 0 {
|
|
t.Errorf("UpdateOrderExecutionLimits empty minimum base amount; Pair: %s Expected Limit: %v", pair, limits.MinimumBaseAmount)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAppendOptionalDelimiter(t *testing.T) {
|
|
t.Parallel()
|
|
curr1, err := currency.NewPairFromString("BTCUSD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
b.appendOptionalDelimiter(&curr1)
|
|
if curr1.Delimiter != "" {
|
|
t.Errorf("Expected no delimiter, received %v", curr1.Delimiter)
|
|
}
|
|
curr2, err := currency.NewPairFromString("DUSK:USD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
curr2.Delimiter = ""
|
|
b.appendOptionalDelimiter(&curr2)
|
|
if curr2.Delimiter != ":" {
|
|
t.Errorf("Expected \":\" as a delimiter, received %v", curr2.Delimiter)
|
|
}
|
|
}
|
|
|
|
func TestGetPlatformStatus(t *testing.T) {
|
|
t.Parallel()
|
|
result, err := b.GetPlatformStatus(context.Background())
|
|
if err != nil {
|
|
t.Errorf("TestGetPlatformStatus error: %s", err)
|
|
}
|
|
|
|
if result != bitfinexOperativeMode && result != bitfinexMaintenanceMode {
|
|
t.Errorf("TestGetPlatformStatus unexpected response code")
|
|
}
|
|
}
|
|
|
|
func TestGetTickerBatch(t *testing.T) {
|
|
t.Parallel()
|
|
ticks, err := b.GetTickerBatch(context.Background())
|
|
require.NoError(t, err, "GetTickerBatch should not error")
|
|
require.NotEmpty(t, ticks, "GetTickerBatch should return some ticks")
|
|
require.Contains(t, ticks, "tBTCUSD", "Ticker batch must contain tBTCUSD")
|
|
checkTradeTick(t, ticks["tBTCUSD"])
|
|
require.Contains(t, ticks, "fUSD", "Ticker batch must contain fUSD")
|
|
checkTradeTick(t, ticks["fUSD"])
|
|
}
|
|
|
|
func TestGetTicker(t *testing.T) {
|
|
t.Parallel()
|
|
tick, err := b.GetTicker(context.Background(), "tBTCUSD")
|
|
require.NoError(t, err, "GetTicker should not error")
|
|
checkTradeTick(t, tick)
|
|
}
|
|
|
|
func TestTickerFromResp(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := tickerFromResp("tBTCUSD", []any{100.0, nil, 100.0, nil, nil, nil, nil, nil, nil, nil})
|
|
assert.ErrorIs(t, err, errTickerInvalidResp, "tickerFromResp should error correctly")
|
|
assert.ErrorContains(t, err, "BidSize", "tickerFromResp should error correctly")
|
|
assert.ErrorContains(t, err, "tBTCUSD", "tickerFromResp should error correctly")
|
|
|
|
_, err = tickerFromResp("tBTCUSD", []any{100.0, nil, 100.0, nil, nil, nil, nil, nil, nil})
|
|
assert.ErrorIs(t, err, errTickerInvalidFieldCount, "tickerFromResp should error correctly")
|
|
assert.ErrorContains(t, err, "tBTCUSD", "tickerFromResp should error correctly")
|
|
|
|
tick, err := tickerFromResp("tBTCUSD", []any{1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10})
|
|
require.NoError(t, err, "tickerFromResp should error correctly")
|
|
assert.Equal(t, 1.1, tick.Bid, "Tick Bid should be correct")
|
|
assert.Equal(t, 2.2, tick.BidSize, "Tick BidSize should be correct")
|
|
assert.Equal(t, 3.3, tick.Ask, "Tick Ask should be correct")
|
|
assert.Equal(t, 4.4, tick.AskSize, "Tick AskSize should be correct")
|
|
assert.Equal(t, 5.5, tick.DailyChange, "Tick DailyChange should be correct")
|
|
assert.Equal(t, 6.6, tick.DailyChangePerc, "Tick DailyChangePerc should be correct")
|
|
assert.Equal(t, 7.7, tick.Last, "Tick Last should be correct")
|
|
assert.Equal(t, 8.8, tick.Volume, "Tick Volume should be correct")
|
|
assert.Equal(t, 9.9, tick.High, "Tick High should be correct")
|
|
assert.Equal(t, 10.10, tick.Low, "Tick Low should be correct")
|
|
|
|
_, err = tickerFromResp("fBTC", []any{100.0, nil, 100.0, nil, nil, nil, nil, nil, nil, nil})
|
|
assert.ErrorIs(t, err, errTickerInvalidFieldCount, "tickerFromResp should delegate to tickerFromFundingResp and error correctly")
|
|
assert.ErrorContains(t, err, "fBTC", "tickerFromResp should delegate to tickerFromFundingResp and error correctly")
|
|
}
|
|
|
|
func TestTickerFromFundingResp(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := tickerFromFundingResp("fBTC", []any{nil, 100.0, nil, 100.0, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil})
|
|
assert.ErrorIs(t, err, errTickerInvalidResp, "tickerFromFundingResp should error correctly")
|
|
assert.ErrorContains(t, err, "FlashReturnRate", "tickerFromFundingResp should error correctly")
|
|
assert.ErrorContains(t, err, "fBTC", "tickerFromFundingResp should error correctly")
|
|
|
|
_, err = tickerFromFundingResp("fBTC", []any{100.0, nil, 100.0, nil, nil, nil, nil, nil, nil})
|
|
assert.ErrorIs(t, err, errTickerInvalidFieldCount, "tickerFromFundingResp should error correctly")
|
|
assert.ErrorContains(t, err, "fBTC", "tickerFromFundingResp should error correctly")
|
|
|
|
tick, err := tickerFromFundingResp("fBTC", []any{1.1, 2.2, 3.0, 4.4, 5.5, 6.0, 7.7, 8.8, 9.9, 10.10, 11.11, 12.12, 13.13, nil, nil, 15.15})
|
|
require.NoError(t, err, "tickerFromFundingResp should error correctly")
|
|
assert.Equal(t, 1.1, tick.FlashReturnRate, "Tick FlashReturnRate should be correct")
|
|
assert.Equal(t, 2.2, tick.Bid, "Tick Bid should be correct")
|
|
assert.Equal(t, int64(3), tick.BidPeriod, "Tick BidPeriod should be correct")
|
|
assert.Equal(t, 4.4, tick.BidSize, "Tick BidSize should be correct")
|
|
assert.Equal(t, 5.5, tick.Ask, "Tick Ask should be correct")
|
|
assert.Equal(t, int64(6), tick.AskPeriod, "Tick AskPeriod should be correct")
|
|
assert.Equal(t, 7.7, tick.AskSize, "Tick AskSize should be correct")
|
|
assert.Equal(t, 8.8, tick.DailyChange, "Tick DailyChange should be correct")
|
|
assert.Equal(t, 9.9, tick.DailyChangePerc, "Tick DailyChangePerc should be correct")
|
|
assert.Equal(t, 10.10, tick.Last, "Tick Last should be correct")
|
|
assert.Equal(t, 11.11, tick.Volume, "Tick Volume should be correct")
|
|
assert.Equal(t, 12.12, tick.High, "Tick High should be correct")
|
|
assert.Equal(t, 13.13, tick.Low, "Tick Low should be correct")
|
|
assert.Equal(t, 15.15, tick.FFRAmountAvailable, "Tick FFRAmountAvailable should be correct")
|
|
}
|
|
|
|
func TestGetTickerFunding(t *testing.T) {
|
|
t.Parallel()
|
|
tick, err := b.GetTicker(context.Background(), "fUSD")
|
|
require.NoError(t, err, "GetTicker should not error")
|
|
checkFundingTick(t, tick)
|
|
}
|
|
|
|
func checkTradeTick(tb testing.TB, tick *Ticker) {
|
|
tb.Helper()
|
|
assert.Positive(tb, tick.Bid, "Tick Bid should be positive")
|
|
assert.Positive(tb, tick.BidSize, "Tick BidSize should be positive")
|
|
assert.Positive(tb, tick.Ask, "Tick Ask should be positive")
|
|
assert.Positive(tb, tick.AskSize, "Tick AskSize should be positive")
|
|
assert.Positive(tb, tick.Last, "Tick Last should be positive")
|
|
// Can't test DailyChange*, Volume, High or Low without false positives when they're occasionally 0
|
|
}
|
|
|
|
func checkFundingTick(tb testing.TB, tick *Ticker) {
|
|
tb.Helper()
|
|
assert.NotZero(tb, tick.FlashReturnRate, "Tick FlashReturnRate should not be zero")
|
|
assert.Positive(tb, tick.Bid, "Tick Bid should be positive")
|
|
assert.Positive(tb, tick.BidPeriod, "Tick BidPeriod should be positive")
|
|
assert.Positive(tb, tick.BidSize, "Tick BidSize should be positive")
|
|
assert.Positive(tb, tick.Ask, "Tick Ask should be positive")
|
|
assert.Positive(tb, tick.AskPeriod, "Tick AskPeriod should be positive")
|
|
assert.Positive(tb, tick.AskSize, "Tick AskSize should be positive")
|
|
assert.Positive(tb, tick.Last, "Tick Last should be positive")
|
|
assert.Positive(tb, tick.FFRAmountAvailable, "Tick FFRAmountavailable should be positive")
|
|
}
|
|
|
|
func TestGetTrades(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := b.GetTrades(context.Background(), "tBTCUSD", 5, 0, 0, false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderbook(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := b.GetOrderbook(context.Background(), "tBTCUSD", "R0", 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.GetOrderbook(context.Background(), "fUSD", "R0", 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.GetOrderbook(context.Background(), "tBTCUSD", "P0", 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.GetOrderbook(context.Background(), "fUSD", "P0", 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.GetOrderbook(context.Background(), "tLINK:UST", "P0", 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetStats(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := b.GetStats(context.Background(), "btcusd")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetFundingBook(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := b.GetFundingBook(context.Background(), "usd")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetLends(t *testing.T) {
|
|
t.Parallel()
|
|
_, err := b.GetLends(context.Background(), "usd", nil)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetCandles(t *testing.T) {
|
|
t.Parallel()
|
|
e := time.Now().Add(-time.Hour * 2).Truncate(time.Hour)
|
|
s := e.Add(-time.Hour * 4)
|
|
_, err := b.GetCandles(context.Background(), "fUST", "1D", s.UnixMilli(), e.UnixMilli(), 10000, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetLeaderboard(t *testing.T) {
|
|
t.Parallel()
|
|
// Test invalid key
|
|
_, err := b.GetLeaderboard(context.Background(), "", "", "", 0, 0, "", "")
|
|
if err == nil {
|
|
t.Error("an error should have been thrown for an invalid key")
|
|
}
|
|
// Test default
|
|
_, err = b.GetLeaderboard(context.Background(),
|
|
LeaderboardUnrealisedProfitInception,
|
|
"1M",
|
|
"tGLOBAL:USD",
|
|
0,
|
|
0,
|
|
"",
|
|
"")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Test params
|
|
var result []LeaderboardEntry
|
|
result, err = b.GetLeaderboard(context.Background(),
|
|
LeaderboardUnrealisedProfitInception,
|
|
"1M",
|
|
"tGLOBAL:USD",
|
|
-1,
|
|
1000,
|
|
"1582695181661",
|
|
"1583299981661")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(result) == 0 {
|
|
t.Error("should have retrieved leaderboard data")
|
|
}
|
|
}
|
|
|
|
func TestGetAccountFees(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
|
|
_, err := b.UpdateAccountInfo(context.Background(), asset.Spot)
|
|
if err != nil {
|
|
t.Error("GetAccountInfo error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetWithdrawalFee(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetWithdrawalFees(context.Background())
|
|
if err != nil {
|
|
t.Error("GetAccountInfo error", err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountSummary(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetAccountSummary(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestNewDeposit(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.NewDeposit(context.Background(), "blabla", "testwallet", 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.NewDeposit(context.Background(), "bitcoin", "testwallet", 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.NewDeposit(context.Background(), "ripple", "", 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetKeyPermissions(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetKeyPermissions(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetMarginInfo(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountBalance(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetAccountBalance(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAccountInfo(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.FetchAccountInfo(context.Background(), asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWalletTransfer(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.WalletTransfer(context.Background(), 0.01, "btc", "bla", "bla")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestNewOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.NewOrder(context.Background(),
|
|
"BTCUSD",
|
|
order.Limit.Lower(),
|
|
-1,
|
|
2,
|
|
false,
|
|
true)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestUpdateTicker(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := b.UpdateTicker(context.Background(), btcusdPair, asset.Spot)
|
|
assert.NoError(t, common.ExcludeError(err, ticker.ErrBidEqualsAsk), "UpdateTicker may only error about locked markets")
|
|
}
|
|
|
|
func TestUpdateTickers(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
updatePairsOnce(t)
|
|
|
|
assets := b.GetAssetTypes(false)
|
|
for _, a := range assets {
|
|
avail, err := b.GetAvailablePairs(a)
|
|
require.NoError(t, err, "GetAvailablePairs should not error")
|
|
|
|
err = b.CurrencyPairs.StorePairs(a, avail, true)
|
|
require.NoError(t, err, "StorePairs should not error")
|
|
|
|
err = b.UpdateTickers(context.Background(), a)
|
|
require.NoError(t, common.ExcludeError(err, ticker.ErrBidEqualsAsk), "UpdateTickers may only error about locked markets")
|
|
|
|
// Bitfinex leaves delisted pairs in Available info/conf endpoints
|
|
// We want to assert that most pairs are valid, so we'll check that no more than 5% are erroring
|
|
acceptableThreshold := 95.0
|
|
okay := 0.0
|
|
var errs error
|
|
for _, p := range avail {
|
|
if _, err = ticker.GetTicker(b.Name, p, a); err != nil {
|
|
errs = common.AppendError(errs, err)
|
|
} else {
|
|
okay++
|
|
}
|
|
}
|
|
if !assert.Greater(t, okay/float64(len(avail))*100.0, acceptableThreshold, "At least %.f%% of %s tickers should not error", acceptableThreshold, a) {
|
|
assert.NoError(t, errs, "Collection of all the ticker errors")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNewOrderMulti(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
newOrder := []PlaceOrder{
|
|
{
|
|
Symbol: "BTCUSD",
|
|
Amount: 1,
|
|
Price: 1,
|
|
Exchange: "bitfinex",
|
|
Side: order.Buy.Lower(),
|
|
Type: order.Limit.Lower(),
|
|
},
|
|
}
|
|
|
|
_, err := b.NewOrderMulti(context.Background(), newOrder)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.CancelExistingOrder(context.Background(), 1337)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelMultipleOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.CancelMultipleOrders(context.Background(), []int64{1337, 1336})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelAllOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.CancelAllExistingOrders(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestReplaceOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.ReplaceOrder(context.Background(), 1337, "BTCUSD",
|
|
1, 1, true, order.Limit.Lower(), false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOrderStatus(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetOrderStatus(context.Background(), 1337)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOpenOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetOpenOrders(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.GetOpenOrders(context.Background(), 1, 2, 3, 4)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetActivePositions(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetActivePositions(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestClaimPosition(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.ClaimPosition(context.Background(), 1337)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetBalanceHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetBalanceHistory(context.Background(),
|
|
"USD", time.Time{}, time.Time{}, 1, "deposit")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMovementHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetMovementHistory(context.Background(), "USD", "bitcoin", time.Time{}, time.Time{}, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetTradeHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetTradeHistory(context.Background(),
|
|
"BTCUSD", time.Time{}, time.Time{}, 1, 0)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestNewOffer(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.NewOffer(context.Background(), "BTC", 1, 1, 1, "loan")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelOffer(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.CancelOffer(context.Background(), 1337)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetWithdrawalsHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetWithdrawalsHistory(context.Background(), currency.BTC, asset.Spot)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetOfferStatus(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetOfferStatus(context.Background(), 1337)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetActiveCredits(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetActiveCredits(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetActiveOffers(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetActiveOffers(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetActiveMarginFunding(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetActiveMarginFunding(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetUnusedMarginFunds(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetUnusedMarginFunds(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetMarginTotalTakenFunds(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetMarginTotalTakenFunds(context.Background())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCloseMarginFunding(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.CloseMarginFunding(context.Background(), 1337)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func setFeeBuilder() *exchange.FeeBuilder {
|
|
return &exchange.FeeBuilder{
|
|
Amount: 1,
|
|
FeeType: exchange.CryptocurrencyTradeFee,
|
|
Pair: currency.NewPair(currency.BTC, currency.LTC),
|
|
PurchasePrice: 1,
|
|
}
|
|
}
|
|
|
|
// TestGetFeeByTypeOfflineTradeFee logic test
|
|
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
|
|
var feeBuilder = setFeeBuilder()
|
|
_, err := b.GetFeeByType(context.Background(), feeBuilder)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) {
|
|
if feeBuilder.FeeType != exchange.OfflineTradeFee {
|
|
t.Errorf("Expected %v, received %v", exchange.OfflineTradeFee, feeBuilder.FeeType)
|
|
}
|
|
} else {
|
|
if feeBuilder.FeeType != exchange.CryptocurrencyTradeFee {
|
|
t.Errorf("Expected %v, received %v", exchange.CryptocurrencyTradeFee, feeBuilder.FeeType)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetFee(t *testing.T) {
|
|
var feeBuilder = setFeeBuilder()
|
|
t.Parallel()
|
|
|
|
if sharedtestvalues.AreAPICredentialsSet(b) {
|
|
// CryptocurrencyTradeFee Basic
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyTradeFee High quantity
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.Amount = 1000
|
|
feeBuilder.PurchasePrice = 1000
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyTradeFee IsMaker
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.IsMaker = true
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyTradeFee Negative purchase price
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.PurchasePrice = -1000
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// CryptocurrencyWithdrawalFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// CryptocurrencyDepositFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.CryptocurrencyDepositFee
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// InternationalBankDepositFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.InternationalBankDepositFee
|
|
feeBuilder.FiatCurrency = currency.HKD
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// InternationalBankWithdrawalFee Basic
|
|
feeBuilder = setFeeBuilder()
|
|
feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee
|
|
feeBuilder.FiatCurrency = currency.HKD
|
|
if _, err := b.GetFee(context.Background(), feeBuilder); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestFormatWithdrawPermissions(t *testing.T) {
|
|
t.Parallel()
|
|
expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.AutoWithdrawFiatWithAPIPermissionText
|
|
withdrawPermissions := b.FormatWithdrawPermissions()
|
|
if withdrawPermissions != expectedResult {
|
|
t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions)
|
|
}
|
|
}
|
|
|
|
func TestGetActiveOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
var getOrdersRequest = order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
AssetType: asset.Spot,
|
|
Side: order.AnySide,
|
|
}
|
|
|
|
_, err := b.GetActiveOrders(context.Background(), &getOrdersRequest)
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Errorf("Could not get open orders: %s", err)
|
|
} else if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
}
|
|
|
|
func TestGetOrderHistory(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
var getOrdersRequest = order.MultiOrderRequest{
|
|
Type: order.AnyType,
|
|
AssetType: asset.Spot,
|
|
Side: order.AnySide,
|
|
}
|
|
_, err := b.GetOrderHistory(context.Background(), &getOrdersRequest)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
|
|
// ----------------------------------------------------------------------------------------------------------------------------
|
|
func TestSubmitOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)
|
|
var orderSubmission = &order.Submit{
|
|
Exchange: b.Name,
|
|
Pair: currency.Pair{
|
|
Delimiter: "_",
|
|
Base: currency.XRP,
|
|
Quote: currency.USD,
|
|
},
|
|
AssetType: asset.Spot,
|
|
Side: order.Sell,
|
|
Type: order.Limit,
|
|
Price: 1000,
|
|
Amount: 20,
|
|
ClientID: "meowOrder",
|
|
}
|
|
response, err := b.SubmitOrder(context.Background(), orderSubmission)
|
|
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Fatalf("Could not place order: %v", err)
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && response.Status != order.New {
|
|
t.Error("Order not placed")
|
|
}
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
}
|
|
|
|
func TestCancelExchangeOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)
|
|
|
|
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
|
var orderCancellation = &order.Cancel{
|
|
OrderID: "1",
|
|
WalletAddress: core.BitcoinDonationAddress,
|
|
AccountID: "1",
|
|
Pair: currencyPair,
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
err := b.CancelOrder(context.Background(), orderCancellation)
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Errorf("Could not cancel orders: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestCancelAllExchangeOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)
|
|
|
|
currencyPair := currency.NewPair(currency.LTC, currency.BTC)
|
|
var orderCancellation = &order.Cancel{
|
|
OrderID: "1",
|
|
WalletAddress: core.BitcoinDonationAddress,
|
|
AccountID: "1",
|
|
Pair: currencyPair,
|
|
AssetType: asset.Spot,
|
|
}
|
|
|
|
resp, err := b.CancelAllOrders(context.Background(), orderCancellation)
|
|
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Errorf("Could not cancel orders: %v", err)
|
|
}
|
|
|
|
if len(resp.Status) > 0 {
|
|
t.Errorf("%v orders failed to cancel", len(resp.Status))
|
|
}
|
|
}
|
|
|
|
func TestModifyOrder(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
_, err := b.ModifyOrder(
|
|
context.Background(),
|
|
&order.Modify{
|
|
OrderID: "1337",
|
|
AssetType: asset.Spot,
|
|
Pair: currency.NewPair(currency.BTC, currency.USD),
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWithdraw(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)
|
|
|
|
withdrawCryptoRequest := withdraw.Request{
|
|
Exchange: b.Name,
|
|
Amount: -1,
|
|
Currency: currency.USDT,
|
|
Description: "WITHDRAW IT ALL",
|
|
Crypto: withdraw.CryptoRequest{
|
|
Address: "0x1nv4l1d",
|
|
Chain: "tetheruse",
|
|
},
|
|
}
|
|
|
|
_, err := b.WithdrawCryptocurrencyFunds(context.Background(),
|
|
&withdrawCryptoRequest)
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Errorf("Withdraw failed to be placed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestWithdrawFiat(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)
|
|
|
|
var withdrawFiatRequest = withdraw.Request{
|
|
Amount: -1,
|
|
Currency: currency.USD,
|
|
Description: "WITHDRAW IT ALL",
|
|
Fiat: withdraw.FiatRequest{
|
|
WireCurrency: currency.USD.String(),
|
|
},
|
|
}
|
|
|
|
_, err := b.WithdrawFiatFunds(context.Background(), &withdrawFiatRequest)
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Errorf("Withdraw failed to be placed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestWithdrawInternationalBank(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)
|
|
|
|
var withdrawFiatRequest = withdraw.Request{
|
|
Amount: -1,
|
|
Currency: currency.BTC,
|
|
Description: "WITHDRAW IT ALL",
|
|
Fiat: withdraw.FiatRequest{
|
|
WireCurrency: currency.USD.String(),
|
|
RequiresIntermediaryBank: true,
|
|
IsExpressWire: false,
|
|
IntermediaryBankAccountNumber: 12345,
|
|
IntermediaryBankAddress: "123 Fake St",
|
|
IntermediaryBankCity: "Tarry Town",
|
|
IntermediaryBankCountry: "Hyrule",
|
|
IntermediaryBankName: "Federal Reserve Bank",
|
|
IntermediarySwiftCode: "Taylor",
|
|
},
|
|
}
|
|
|
|
_, err := b.WithdrawFiatFundsToInternationalBank(context.Background(),
|
|
&withdrawFiatRequest)
|
|
if !sharedtestvalues.AreAPICredentialsSet(b) && err == nil {
|
|
t.Error("Expecting an error when no keys are set")
|
|
}
|
|
if sharedtestvalues.AreAPICredentialsSet(b) && err != nil {
|
|
t.Errorf("Withdraw failed to be placed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestGetDepositAddress(t *testing.T) {
|
|
t.Parallel()
|
|
if sharedtestvalues.AreAPICredentialsSet(b) {
|
|
_, err := b.GetDepositAddress(context.Background(), currency.USDT, "", "TETHERUSE")
|
|
if err != nil {
|
|
t.Error("GetDepositAddress() error", err)
|
|
}
|
|
} else {
|
|
_, err := b.GetDepositAddress(context.Background(), currency.BTC, "deposit", "")
|
|
if err == nil {
|
|
t.Error("GetDepositAddress() error cannot be nil")
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestWsAuth dials websocket, sends login request.
|
|
func TestWsAuth(t *testing.T) {
|
|
if !b.Websocket.IsEnabled() {
|
|
t.Skip(stream.ErrWebsocketNotEnabled.Error())
|
|
}
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
if !b.API.AuthenticatedWebsocketSupport {
|
|
t.Skip("Authentecated API support not enabled")
|
|
}
|
|
setupWs(t)
|
|
assert.True(t, b.Websocket.CanUseAuthenticatedEndpoints(), "CanUseAuthenticatedEndpoints should be turned on")
|
|
|
|
var resp map[string]interface{}
|
|
catcher := func() (ok bool) {
|
|
select {
|
|
case v := <-b.Websocket.DataHandler:
|
|
resp, ok = v.(map[string]interface{})
|
|
default:
|
|
}
|
|
return
|
|
}
|
|
|
|
if assert.Eventually(t, catcher, sharedtestvalues.WebsocketResponseDefaultTimeout, time.Millisecond*10, "Auth response should arrive") {
|
|
assert.Equal(t, "auth", resp["event"], "event should be correct")
|
|
assert.Equal(t, "OK", resp["status"], "status should be correct")
|
|
assert.NotEmpty(t, resp["auth_id"], "status should be correct")
|
|
}
|
|
}
|
|
|
|
// TestWsSubscribe tests Subscribe and Unsubscribe functionality
|
|
// See also TestSubscribeReq which covers key and symbol conversion
|
|
func TestWsSubscribe(t *testing.T) {
|
|
setupWs(t)
|
|
err := b.Subscribe([]subscription.Subscription{{Channel: wsTicker, Pair: currency.NewPair(currency.BTC, currency.USD), Asset: asset.Spot}})
|
|
assert.NoError(t, err, "Subrcribe should not error")
|
|
catcher := func() (ok bool) {
|
|
i := <-b.Websocket.DataHandler
|
|
_, ok = i.(*ticker.Price)
|
|
return
|
|
}
|
|
assert.Eventually(t, catcher, sharedtestvalues.WebsocketResponseDefaultTimeout, time.Millisecond*10, "Ticker response should arrive")
|
|
|
|
subs, err := b.GetSubscriptions()
|
|
assert.NoError(t, err, "GetSubscriptions should not error")
|
|
assert.Len(t, subs, 1, "We should only have 1 subscription; subID subscription should have been Removed by subscribeToChan")
|
|
|
|
err = b.Subscribe([]subscription.Subscription{{Channel: wsTicker, Pair: currency.NewPair(currency.BTC, currency.USD), Asset: asset.Spot}})
|
|
assert.ErrorIs(t, err, stream.ErrSubscriptionFailure, "Duplicate subscription should error correctly")
|
|
catcher = func() bool {
|
|
i := <-b.Websocket.DataHandler
|
|
if e, ok := i.(error); ok {
|
|
if assert.ErrorIs(t, e, stream.ErrSubscriptionFailure, "Error should go to DataHandler") {
|
|
assert.ErrorContains(t, e, "subscribe: dup (code: 10301)", "Error should contain message and code")
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
assert.Eventually(t, catcher, sharedtestvalues.WebsocketResponseDefaultTimeout, time.Millisecond*10, "error response should arrive")
|
|
|
|
subs, err = b.GetSubscriptions()
|
|
assert.NoError(t, err, "GetSubscriptions should not error")
|
|
assert.Len(t, subs, 1, "We should only have one subscription after an error attempt")
|
|
|
|
err = b.Unsubscribe(subs)
|
|
assert.NoError(t, err, "Unsubscribing should not error")
|
|
|
|
chanID, ok := subs[0].Key.(int)
|
|
assert.True(t, ok, "sub.Key should be an int")
|
|
|
|
err = b.Unsubscribe(subs)
|
|
assert.ErrorIs(t, err, stream.ErrUnsubscribeFailure, "Unsubscribe should error")
|
|
assert.ErrorContains(t, err, strconv.Itoa(chanID), "Unsubscribe should contain correct chanId")
|
|
assert.ErrorContains(t, err, "unsubscribe: invalid (code: 10400)", "Unsubscribe should contain correct upstream error")
|
|
|
|
err = b.Subscribe([]subscription.Subscription{{
|
|
Channel: wsTicker,
|
|
Pair: currency.NewPair(currency.BTC, currency.USD),
|
|
Asset: asset.Spot,
|
|
Params: map[string]interface{}{"key": "tBTCUSD"},
|
|
}})
|
|
assert.ErrorIs(t, err, stream.ErrSubscriptionFailure, "Trying to use a 'key' param should error ErrSubscriptionFailure")
|
|
assert.ErrorIs(t, err, errParamNotAllowed, "Trying to use a 'key' param should error errParamNotAllowed")
|
|
}
|
|
|
|
// TestSubscribeReq tests the channel to request map marshalling
|
|
func TestSubscribeReq(t *testing.T) {
|
|
c := &subscription.Subscription{
|
|
Channel: wsCandles,
|
|
Pair: currency.NewPair(currency.BTC, currency.USD),
|
|
Asset: asset.MarginFunding,
|
|
Params: map[string]interface{}{
|
|
CandlesPeriodKey: "30",
|
|
},
|
|
}
|
|
r, err := subscribeReq(c)
|
|
assert.NoError(t, err, "subscribeReq should not error")
|
|
assert.Equal(t, "trade:1m:fBTCUSD:p30", r["key"], "key contain period and default timeframe")
|
|
|
|
c.Params = map[string]interface{}{
|
|
CandlesTimeframeKey: "15m",
|
|
}
|
|
r, err = subscribeReq(c)
|
|
assert.NoError(t, err, "subscribeReq should not error")
|
|
assert.Equal(t, "trade:15m:fBTCUSD", r["key"], "key should be contain specific timeframe and no period")
|
|
|
|
c = &subscription.Subscription{
|
|
Channel: wsBook,
|
|
Pair: currency.NewPair(currency.BTC, currency.DOGE),
|
|
Asset: asset.Spot,
|
|
}
|
|
r, err = subscribeReq(c)
|
|
assert.NoError(t, err, "subscribeReq should not error")
|
|
assert.Equal(t, "tBTC:DOGE", r["symbol"], "symbol should use colon delimiter if a currency is > 3 chars")
|
|
|
|
c.Pair = currency.NewPair(currency.BTC, currency.LTC)
|
|
r, err = subscribeReq(c)
|
|
assert.NoError(t, err, "subscribeReq should not error")
|
|
assert.Equal(t, "tBTCLTC", r["symbol"], "symbol should not use colon delimiter if both currencies < 3 chars")
|
|
}
|
|
|
|
// TestWsPlaceOrder dials websocket, sends order request.
|
|
func TestWsPlaceOrder(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
|
|
_, err := b.WsNewOrder(&WsNewOrderRequest{
|
|
GroupID: 1,
|
|
Type: "EXCHANGE LIMIT",
|
|
Symbol: "tXRPUSD",
|
|
Amount: -20,
|
|
Price: 1000,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestWsCancelOrder dials websocket, sends cancel request.
|
|
func TestWsCancelOrder(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
if err := b.WsCancelOrder(1234); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestWsCancelOrder dials websocket, sends modify request.
|
|
func TestWsUpdateOrder(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
err := b.WsModifyOrder(&WsUpdateOrderRequest{
|
|
OrderID: 1234,
|
|
Price: -111,
|
|
Amount: 111,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestWsCancelAllOrders dials websocket, sends cancel all request.
|
|
func TestWsCancelAllOrders(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
if err := b.WsCancelAllOrders(); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestWsCancelAllOrders dials websocket, sends cancel all request.
|
|
func TestWsCancelMultiOrders(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
err := b.WsCancelMultiOrders([]int64{1, 2, 3, 4})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestWsNewOffer dials websocket, sends new offer request.
|
|
func TestWsNewOffer(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
err := b.WsNewOffer(&WsNewOfferRequest{
|
|
Type: order.Limit.String(),
|
|
Symbol: "fBTC",
|
|
Amount: -10,
|
|
Rate: 10,
|
|
Period: 30,
|
|
})
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestWsCancelOffer dials websocket, sends cancel offer request.
|
|
func TestWsCancelOffer(t *testing.T) {
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
setupWs(t)
|
|
if err := b.WsCancelOffer(1234); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsSubscribedResponse(t *testing.T) {
|
|
m, err := b.Websocket.Match.Set("subscribe:waiter1")
|
|
assert.NoError(t, err, "Setting a matcher should not error")
|
|
err = b.wsHandleData([]byte(`{"event":"subscribed","channel":"ticker","chanId":224555,"subId":"waiter1","symbol":"tBTCUSD","pair":"BTCUSD"}`))
|
|
if assert.Error(t, err, "Should error if sub is not registered yet") {
|
|
assert.ErrorIs(t, err, stream.ErrSubscriptionFailure, "Should error SubFailure if sub isn't registered yet")
|
|
assert.ErrorIs(t, err, stream.ErrSubscriptionFailure, "Should error SubNotFound if sub isn't registered yet")
|
|
assert.ErrorContains(t, err, "waiter1", "Should error containing subID if")
|
|
}
|
|
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Key: "waiter1"})
|
|
err = b.wsHandleData([]byte(`{"event":"subscribed","channel":"ticker","chanId":224555,"subId":"waiter1","symbol":"tBTCUSD","pair":"BTCUSD"}`))
|
|
assert.NoError(t, err, "wsHandleData should not error")
|
|
if assert.NotEmpty(t, m.C, "Matcher should have received a sub notification") {
|
|
msg := <-m.C
|
|
cID, err := jsonparser.GetInt(msg, "chanId")
|
|
assert.NoError(t, err, "Should get chanId from sub notification without error")
|
|
assert.EqualValues(t, 224555, cID, "Should get the correct chanId through the matcher notification")
|
|
}
|
|
m.Cleanup()
|
|
}
|
|
|
|
func TestWsOrderBook(t *testing.T) {
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Key: 23405, Asset: asset.Spot, Pair: btcusdPair, Channel: wsBook})
|
|
pressXToJSON := `[23405,[[38334303613,9348.8,0.53],[38334308111,9348.8,5.98979404],[38331335157,9344.1,1.28965787],[38334302803,9343.8,0.08230094],[38334279092,9343,0.8],[38334307036,9342.938663676,0.8],[38332749107,9342.9,0.2],[38332277330,9342.8,0.85],[38329406786,9342,0.1432012],[38332841570,9341.947288638,0.3],[38332163238,9341.7,0.3],[38334303384,9341.6,0.324],[38332464840,9341.4,0.5],[38331935870,9341.2,0.5],[38334312082,9340.9,0.02126899],[38334261292,9340.8,0.26763],[38334138680,9340.625455254,0.12],[38333896802,9339.8,0.85],[38331627527,9338.9,1.57863959],[38334186713,9338.9,0.26769],[38334305819,9338.8,2.999],[38334211180,9338.75285796,3.999],[38334310699,9337.8,0.10679883],[38334307414,9337.5,1],[38334179822,9337.1,0.26773],[38334306600,9336.659955102,1.79],[38334299667,9336.6,1.1],[38334306452,9336.6,0.13979771],[38325672859,9336.3,1.25],[38334311646,9336.2,1],[38334258509,9336.1,0.37],[38334310592,9336,1.79],[38334310378,9335.6,1.43],[38334132444,9335.2,0.26777],[38331367325,9335,0.07],[38334310703,9335,0.10680562],[38334298209,9334.7,0.08757301],[38334304857,9334.456899462,0.291],[38334309940,9334.088390727,0.0725],[38334310377,9333.7,1.2868],[38334297615,9333.607784,0.1108],[38334095188,9333.3,0.26785],[38334228913,9332.7,0.40861186],[38334300526,9332.363996604,0.3884],[38334310701,9332.2,0.10680562],[38334303548,9332.005382871,0.07],[38334311798,9331.8,0.41285228],[38334301012,9331.7,1.7952],[38334089877,9331.4,0.2679],[38321942150,9331.2,0.2],[38334310670,9330,1.069],[38334063096,9329.6,0.26796],[38334310700,9329.4,0.10680562],[38334310404,9329.3,1],[38334281630,9329.1,6.57150597],[38334036864,9327.7,0.26801],[38334310702,9326.6,0.10680562],[38334311799,9326.1,0.50220625],[38334164163,9326,0.219638],[38334309722,9326,1.5],[38333051682,9325.8,0.26807],[38334302027,9325.7,0.75],[38334203435,9325.366592,0.32397696],[38321967613,9325,0.05],[38334298787,9324.9,0.3],[38334301719,9324.8,3.6227592],[38331316716,9324.763454646,0.71442],[38334310698,9323.8,0.10680562],[38334035499,9323.7,0.23431017],[38334223472,9322.670551788,0.42150603],[38334163459,9322.560399006,0.143967],[38321825171,9320.8,2],[38334075805,9320.467496148,0.30772633],[38334075800,9319.916732238,0.61457592],[38333682302,9319.7,0.0011],[38331323088,9319.116771762,0.12913],[38333677480,9319,0.0199],[38334277797,9318.6,0.89],[38325235155,9318.041088,1.20249],[38334310910,9317.82382938,1.79],[38334311811,9317.2,0.61079138],[38334311812,9317.2,0.71937652],[38333298214,9317.1,50],[38334306359,9317,1.79],[38325531545,9316.382823951,0.21263],[38333727253,9316.3,0.02316372],[38333298213,9316.1,45],[38333836479,9316,2.135],[38324520465,9315.9,2.7681],[38334307411,9315.5,1],[38330313617,9315.3,0.84455],[38334077770,9315.294024,0.01248397],[38334286663,9315.294024,1],[38325533762,9315.290315394,2.40498],[38334310018,9315.2,3],[38333682617,9314.6,0.0011],[38334304794,9314.6,0.76364676],[38334304798,9314.3,0.69242113],[38332915733,9313.8,0.0199],[38334084411,9312.8,1],[38334311893,9350.1,-1.015],[38334302734,9350.3,-0.26737],[38334300732,9350.8,-5.2],[38333957619,9351,-0.90677089],[38334300521,9351,-1.6457],[38334301600,9351.012829557,-0.0523],[38334308878,9351.7,-2.5],[38334299570,9351.921544,-0.1015],[38334279367,9352.1,-0.26732],[38334299569,9352.411802928,-0.4036],[38334202773,9353.4,-0.02139404],[38333918472,9353.7,-1.96412776],[38334278782,9354,-0.26731],[38334278606,9355,-1.2785],[38334302105,9355.439221251,-0.79191542],[38313897370,9355.569409242,-0.43363],[38334292995,9355.584296,-0.0979],[38334216989,9355.8,-0.03686414],[38333894025,9355.9,-0.26721],[38334293798,9355.936691952,-0.4311],[38331159479,9356,-0.4204022],[38333918888,9356.1,-1.10885563],[38334298205,9356.4,-0.20124428],[38328427481,9356.5,-0.1],[38333343289,9356.6,-0.41034213],[38334297205,9356.6,-0.08835018],[38334277927,9356.741101161,-0.0737],[38334311645,9356.8,-0.5],[38334309002,9356.9,-5],[38334309736,9357,-0.10680107],[38334306448,9357.4,-0.18645275],[38333693302,9357.7,-0.2672],[38332815159,9357.8,-0.0011],[38331239824,9358.2,-0.02],[38334271608,9358.3,-2.999],[38334311971,9358.4,-0.55],[38333919260,9358.5,-1.9972841],[38334265365,9358.5,-1.7841],[38334277960,9359,-3],[38334274601,9359.020969848,-3],[38326848839,9359.1,-0.84],[38334291080,9359.247048,-0.16199869],[38326848844,9359.4,-1.84],[38333680200,9359.6,-0.26713],[38331326606,9359.8,-0.84454],[38334309738,9359.8,-0.10680107],[38331314707,9359.9,-0.2],[38333919803,9360.9,-1.41177599],[38323651149,9361.33417827,-0.71442],[38333656906,9361.5,-0.26705],[38334035500,9361.5,-0.40861586],[38334091886,9362.4,-6.85940815],[38334269617,9362.5,-4],[38323629409,9362.545858872,-2.40497],[38334309737,9362.7,-0.10680107],[38334312380,9362.7,-3],[38325280830,9362.8,-1.75123],[38326622800,9362.8,-1.05145],[38333175230,9363,-0.0011],[38326848745,9363.2,-0.79],[38334308960,9363.206775564,-0.12],[38333920234,9363.3,-1.25318113],[38326848843,9363.4,-1.29],[38331239823,9363.4,-0.02],[38333209613,9363.4,-0.26719],[38334299964,9364,-0.05583123],[38323470224,9364.161816648,-0.12912],[38334284711,9365,-0.21346019],[38334299594,9365,-2.6757062],[38323211816,9365.073132585,-0.21262],[38334312456,9365.1,-0.11167861],[38333209612,9365.2,-0.26719],[38327770474,9365.3,-0.0073],[38334298788,9365.3,-0.3],[38334075803,9365.409831204,-0.30772637],[38334309740,9365.5,-0.10680107],[38326608767,9365.7,-2.76809],[38333920657,9365.7,-1.25848083],[38329594226,9366.6,-0.02587],[38334311813,9366.7,-4.72290945],[38316386301,9367.39258128,-2.37581],[38334302026,9367.4,-4.5],[38334228915,9367.9,-0.81725458],[38333921381,9368.1,-1.72213641],[38333175678,9368.2,-0.0011],[38334301150,9368.2,-2.654604],[38334297208,9368.3,-0.78036466],[38334309739,9368.3,-0.10680107],[38331227515,9368.7,-0.02],[38331184470,9369,-0.003975],[38334203436,9369.319616,-0.32397695],[38334269964,9369.7,-0.5],[38328386732,9370,-4.11759935],[38332719555,9370,-0.025],[38333921935,9370.5,-1.2224398],[38334258511,9370.5,-0.35],[38326848842,9370.8,-0.34],[38333985038,9370.9,-0.8551502],[38334283018,9370.9,-1],[38326848744,9371,-1.34]],5]`
|
|
err := b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pressXToJSON = `[23405,[7617,52.98726298,7617.1,53.601795929999994,-550.9,-0.0674,7617,8318.92961981,8257.8,7500],6]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pressXToJSON = `[23405,[7617,52.98726298,7617.1,53.601795929999994,-550.9,-0.0674,7617,8318.92961981,8257.8,7500]]`
|
|
assert.NotPanics(t, func() { err = b.wsHandleData([]byte(pressXToJSON)) }, "handleWSBookUpdate should not panic when seqNo is not configured to be sent")
|
|
assert.ErrorIs(t, err, errNoSeqNo, "handleWSBookUpdate should send correct error")
|
|
}
|
|
|
|
func TestWsTradeResponse(t *testing.T) {
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Asset: asset.Spot, Pair: btcusdPair, Channel: wsTrades, Key: 18788})
|
|
pressXToJSON := `[18788,[[412685577,1580268444802,11.1998,176.3],[412685575,1580268444802,5,176.29952759],[412685574,1580268374717,1.99069999,176.41],[412685573,1580268374717,1.00930001,176.41],[412685572,1580268358760,0.9907,176.47],[412685571,1580268324362,0.5505,176.44],[412685570,1580268297270,-0.39040819,176.39],[412685568,1580268297270,-0.39780162,176.46475676],[412685567,1580268283470,-0.09,176.41],[412685566,1580268256536,-2.31310783,176.48],[412685565,1580268256536,-0.59669217,176.49],[412685564,1580268256536,-0.9902,176.49],[412685562,1580268194474,0.9902,176.55],[412685561,1580268186215,0.1,176.6],[412685560,1580268185964,-2.17096773,176.5],[412685559,1580268185964,-1.82903227,176.51],[412685558,1580268181215,2.098914,176.53],[412685557,1580268169844,16.7302,176.55],[412685556,1580268169844,3.25,176.54],[412685555,1580268155725,0.23576115,176.45],[412685553,1580268155725,3,176.44596249],[412685552,1580268155725,3.25,176.44],[412685551,1580268155725,5,176.44],[412685550,1580268155725,0.65830078,176.41],[412685549,1580268155725,0.45063807,176.41],[412685548,1580268153825,-0.67604704,176.39],[412685547,1580268145713,2.5883,176.41],[412685543,1580268087513,12.92927,176.33],[412685542,1580268087513,0.40083,176.33],[412685533,1580268005756,-0.17096773,176.32]]]`
|
|
err := b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsTickerResponse(t *testing.T) {
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Asset: asset.Spot, Pair: btcusdPair, Channel: wsTicker, Key: 11534})
|
|
pressXToJSON := `[11534,[61.304,2228.36155358,61.305,1323.2442970500003,0.395,0.0065,61.371,50973.3020771,62.5,57.421]]`
|
|
err := b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pair, err := currency.NewPairFromString("XAUTF0:USTF0")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Asset: asset.Spot, Pair: pair, Channel: wsTicker, Key: 123412})
|
|
pressXToJSON = `[123412,[61.304,2228.36155358,61.305,1323.2442970500003,0.395,0.0065,61.371,50973.3020771,62.5,57.421]]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pair, err = currency.NewPairFromString("trade:1m:tXRPUSD")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Asset: asset.Spot, Pair: pair, Channel: wsTicker, Key: 123413})
|
|
pressXToJSON = `[123413,[61.304,2228.36155358,61.305,1323.2442970500003,0.395,0.0065,61.371,50973.3020771,62.5,57.421]]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pair, err = currency.NewPairFromString("trade:1m:fZRX:p30")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Asset: asset.Spot, Pair: pair, Channel: wsTicker, Key: 123414})
|
|
pressXToJSON = `[123414,[61.304,2228.36155358,61.305,1323.2442970500003,0.395,0.0065,61.371,50973.3020771,62.5,57.421]]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsCandleResponse(t *testing.T) {
|
|
b.Websocket.AddSuccessfulSubscriptions(subscription.Subscription{Asset: asset.Spot, Pair: btcusdPair, Channel: wsCandles, Key: 343351})
|
|
pressXToJSON := `[343351,[[1574698260000,7379.785503,7383.8,7388.3,7379.785503,1.68829482]]]`
|
|
err := b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pressXToJSON = `[343351,[1574698200000,7399.9,7379.7,7399.9,7371.8,41.63633658]]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsOrderSnapshot(t *testing.T) {
|
|
pressXToJSON := `[0,"os",[[34930659963,null,1574955083558,"tETHUSD",1574955083558,1574955083573,0.201104,0.201104,"EXCHANGE LIMIT",null,null,null,0,"ACTIVE",null,null,120,0,0,0,null,null,null,0,0,null,null,null,"BFX",null,null,null]]]`
|
|
err := b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
pressXToJSON = `[0,"oc",[34930659963,null,1574955083558,"tETHUSD",1574955083558,1574955354487,0.201104,0.201104,"EXCHANGE LIMIT",null,null,null,0,"CANCELED",null,null,120,0,0,0,null,null,null,0,0,null,null,null,"BFX",null,null,null]]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsNotifications(t *testing.T) {
|
|
pressXToJSON := `[0,"n",[1575282446099,"fon-req",null,null,[41238905,null,null,null,-1000,null,null,null,null,null,null,null,null,null,0.002,2,null,null,null,null,null],null,"SUCCESS","Submitting funding bid of 1000.0 USD at 0.2000 for 2 days."]]`
|
|
err := b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
pressXToJSON = `[0,"n",[1575287438.515,"on-req",null,null,[1185815098,null,1575287436979,"tETHUSD",1575287438515,1575287438515,-2.5,-2.5,"LIMIT",null,null,null,0,"ACTIVE",null,null,230,0,0,0,null,null,null,0,null,null,null,null,"API>BFX",null,null,null],null,"SUCCESS","Submitting limit sell order for -2.5 ETH."]]`
|
|
err = b.wsHandleData([]byte(pressXToJSON))
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsFundingOfferSnapshotAndUpdate(t *testing.T) {
|
|
pressXToJSON := `[0,"fos",[[41237920,"fETH",1573912039000,1573912039000,0.5,0.5,"LIMIT",null,null,0,"ACTIVE",null,null,null,0.0024,2,0,0,null,0,null]]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
pressXToJSON = `[0,"fon",[41238747,"fUST",1575026670000,1575026670000,5000,5000,"LIMIT",null,null,0,"ACTIVE",null,null,null,0.006000000000000001,30,0,0,null,0,null]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsFundingCreditSnapshotAndUpdate(t *testing.T) {
|
|
pressXToJSON := `[0,"fcs",[[26223578,"fUST",1,1575052261000,1575296187000,350,0,"ACTIVE",null,null,null,0,30,1575052261000,1575293487000,0,0,null,0,null,0,"tBTCUST"],[26223711,"fUSD",-1,1575291961000,1575296187000,180,0,"ACTIVE",null,null,null,0.002,7,1575282446000,1575295587000,0,0,null,0,null,0,"tETHUSD"]]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
pressXToJSON = `[0,"fcu",[26223578,"fUST",1,1575052261000,1575296787000,350,0,"ACTIVE",null,null,null,0,30,1575052261000,1575293487000,0,0,null,0,null,0,"tBTCUST"]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsFundingLoanSnapshotAndUpdate(t *testing.T) {
|
|
pressXToJSON := `[0,"fls",[[2995442,"fUSD",-1,1575291961000,1575295850000,820,0,"ACTIVE",null,null,null,0.002,7,1575282446000,1575295850000,0,0,null,0,null,0]]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
pressXToJSON = `[0,"fln",[2995444,"fUSD",-1,1575298742000,1575298742000,1000,0,"ACTIVE",null,null,null,0.002,7,1575298742000,1575298742000,0,0,null,0,null,0]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsWalletSnapshot(t *testing.T) {
|
|
pressXToJSON := `[0,"ws",[["exchange","SAN",19.76,0,null,null,null]]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsBalanceUpdate(t *testing.T) {
|
|
const pressXToJSON = `[0,"bu",[4131.85,4131.85]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsMarginInfoUpdate(t *testing.T) {
|
|
const pressXToJSON = `[0,"miu",["base",[-13.014640000000007,0,49331.70267297,49318.68803297,27]]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsFundingInfoUpdate(t *testing.T) {
|
|
const pressXToJSON = `[0,"fiu",["sym","tETHUSD",[149361.09689202666,149639.26293509,830.0182168075556,895.0658432466332]]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestWsFundingTrade(t *testing.T) {
|
|
pressXToJSON := `[0,"fte",[636854,"fUSD",1575282446000,41238905,-1000,0.002,7,null]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
pressXToJSON = `[0,"ftu",[636854,"fUSD",1575282446000,41238905,-1000,0.002,7,null]]`
|
|
if err := b.wsHandleData([]byte(pressXToJSON)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricCandles(t *testing.T) {
|
|
startTime := time.Now().Add(-time.Hour * 24)
|
|
endTime := time.Now().Add(-time.Hour * 20)
|
|
|
|
if _, err := b.GetHistoricCandles(context.Background(), btcusdPair, asset.Spot, kline.OneHour, startTime, endTime); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricCandlesExtended(t *testing.T) {
|
|
startTime := time.Now().Add(-time.Hour * 24)
|
|
endTime := time.Now().Add(-time.Hour * 20)
|
|
|
|
if _, err := b.GetHistoricCandlesExtended(context.Background(), btcusdPair, asset.Spot, kline.OneHour, startTime, endTime); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestFixCasing(t *testing.T) {
|
|
ret, err := b.fixCasing(btcusdPair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tBTCUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
pair, err := currency.NewPairFromString("TBTCUSD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tBTCUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
pair, err = currency.NewPairFromString("tBTCUSD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tBTCUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
ret, err = b.fixCasing(btcusdPair, asset.Margin)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tBTCUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
ret, err = b.fixCasing(btcusdPair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tBTCUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
pair, err = currency.NewPairFromString("FUNETH")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tFUNETH" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
pair, err = currency.NewPairFromString("TNBUSD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tTNBUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
|
|
pair, err = currency.NewPairFromString("tTNBUSD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.Spot)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "tTNBUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
pair, err = currency.NewPairFromStrings("fUSD", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.MarginFunding)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "fUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
pair, err = currency.NewPairFromStrings("USD", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.MarginFunding)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "fUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
|
|
pair, err = currency.NewPairFromStrings("FUSD", "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ret, err = b.fixCasing(pair, asset.MarginFunding)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ret != "fUSD" {
|
|
t.Errorf("unexpected result: %v", ret)
|
|
}
|
|
|
|
_, err = b.fixCasing(currency.NewPair(currency.EMPTYCODE, currency.BTC), asset.MarginFunding)
|
|
if !errors.Is(err, currency.ErrCurrencyPairEmpty) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrCurrencyPairEmpty)
|
|
}
|
|
|
|
_, err = b.fixCasing(currency.NewPair(currency.BTC, currency.EMPTYCODE), asset.MarginFunding)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, nil)
|
|
}
|
|
|
|
_, err = b.fixCasing(currency.EMPTYPAIR, asset.MarginFunding)
|
|
if !errors.Is(err, currency.ErrCurrencyPairEmpty) {
|
|
t.Fatalf("received: '%v' but expected: '%v'", err, currency.ErrCurrencyPairEmpty)
|
|
}
|
|
}
|
|
|
|
func Test_FormatExchangeKlineInterval(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
interval kline.Interval
|
|
output string
|
|
}{
|
|
{
|
|
"OneMin",
|
|
kline.OneMin,
|
|
"1m",
|
|
},
|
|
{
|
|
"OneDay",
|
|
kline.OneDay,
|
|
"1D",
|
|
},
|
|
{
|
|
"OneWeek",
|
|
kline.OneWeek,
|
|
"7D",
|
|
},
|
|
{
|
|
"TwoWeeks",
|
|
kline.OneWeek * 2,
|
|
"14D",
|
|
},
|
|
}
|
|
|
|
for x := range testCases {
|
|
test := testCases[x]
|
|
t.Run(test.name, func(t *testing.T) {
|
|
ret, err := b.FormatExchangeKlineInterval(test.interval)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
if ret != test.output {
|
|
t.Fatalf("unexpected result return expected: %v received: %v", test.output, ret)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetRecentTrades(t *testing.T) {
|
|
t.Parallel()
|
|
if _, err := b.GetRecentTrades(context.Background(), btcusdPair, asset.Spot); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
currencyPair, err := currency.NewPairFromString("USD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = b.GetRecentTrades(context.Background(), currencyPair, asset.Margin)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetHistoricTrades(t *testing.T) {
|
|
t.Parallel()
|
|
if _, err := b.GetHistoricTrades(context.Background(),
|
|
btcusdPair, asset.Spot, time.Now().Add(-time.Minute*15), time.Now()); err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// longer term test
|
|
if _, err := b.GetHistoricTrades(context.Background(),
|
|
btcusdPair, asset.Spot,
|
|
time.Now().Add(-time.Hour*100),
|
|
time.Now().Add(-time.Hour*99)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
var testOb = orderbook.Base{
|
|
Asks: []orderbook.Item{
|
|
{Price: 0.05005, Amount: 0.00000500},
|
|
{Price: 0.05010, Amount: 0.00000500},
|
|
{Price: 0.05015, Amount: 0.00000500},
|
|
{Price: 0.05020, Amount: 0.00000500},
|
|
{Price: 0.05025, Amount: 0.00000500},
|
|
{Price: 0.05030, Amount: 0.00000500},
|
|
{Price: 0.05035, Amount: 0.00000500},
|
|
{Price: 0.05040, Amount: 0.00000500},
|
|
{Price: 0.05045, Amount: 0.00000500},
|
|
{Price: 0.05050, Amount: 0.00000500},
|
|
},
|
|
Bids: []orderbook.Item{
|
|
{Price: 0.05000, Amount: 0.00000500},
|
|
{Price: 0.04995, Amount: 0.00000500},
|
|
{Price: 0.04990, Amount: 0.00000500},
|
|
{Price: 0.04980, Amount: 0.00000500},
|
|
{Price: 0.04975, Amount: 0.00000500},
|
|
{Price: 0.04970, Amount: 0.00000500},
|
|
{Price: 0.04965, Amount: 0.00000500},
|
|
{Price: 0.04960, Amount: 0.00000500},
|
|
{Price: 0.04955, Amount: 0.00000500},
|
|
{Price: 0.04950, Amount: 0.00000500},
|
|
},
|
|
}
|
|
|
|
func TestChecksum(t *testing.T) {
|
|
err := validateCRC32(&testOb, 190468240)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestReOrderbyID(t *testing.T) {
|
|
asks := []orderbook.Item{
|
|
{ID: 4, Price: 100, Amount: 0.00000500},
|
|
{ID: 3, Price: 100, Amount: 0.00000500},
|
|
{ID: 2, Price: 100, Amount: 0.00000500},
|
|
{ID: 1, Price: 100, Amount: 0.00000500},
|
|
{ID: 5, Price: 101, Amount: 0.00000500},
|
|
{ID: 6, Price: 102, Amount: 0.00000500},
|
|
{ID: 8, Price: 103, Amount: 0.00000500},
|
|
{ID: 7, Price: 103, Amount: 0.00000500},
|
|
{ID: 9, Price: 104, Amount: 0.00000500},
|
|
{ID: 10, Price: 105, Amount: 0.00000500},
|
|
}
|
|
reOrderByID(asks)
|
|
|
|
for i := range asks {
|
|
if asks[i].ID != int64(i+1) {
|
|
t.Fatal("order by ID failure")
|
|
}
|
|
}
|
|
|
|
bids := []orderbook.Item{
|
|
{ID: 4, Price: 100, Amount: 0.00000500},
|
|
{ID: 3, Price: 100, Amount: 0.00000500},
|
|
{ID: 2, Price: 100, Amount: 0.00000500},
|
|
{ID: 1, Price: 100, Amount: 0.00000500},
|
|
{ID: 5, Price: 99, Amount: 0.00000500},
|
|
{ID: 6, Price: 98, Amount: 0.00000500},
|
|
{ID: 8, Price: 97, Amount: 0.00000500},
|
|
{ID: 7, Price: 97, Amount: 0.00000500},
|
|
{ID: 9, Price: 96, Amount: 0.00000500},
|
|
{ID: 10, Price: 95, Amount: 0.00000500},
|
|
}
|
|
reOrderByID(bids)
|
|
|
|
for i := range bids {
|
|
if bids[i].ID != int64(i+1) {
|
|
t.Fatal("order by ID failure")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestPopulateAcceptableMethods(t *testing.T) {
|
|
t.Parallel()
|
|
if acceptableMethods.loaded() {
|
|
// we may have been loaded from another test, so reset
|
|
acceptableMethods.m.Lock()
|
|
acceptableMethods.a = make(map[string][]string)
|
|
acceptableMethods.m.Unlock()
|
|
if acceptableMethods.loaded() {
|
|
t.Error("expected false")
|
|
}
|
|
}
|
|
if err := b.PopulateAcceptableMethods(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !acceptableMethods.loaded() {
|
|
t.Error("acceptable method store should be loaded")
|
|
}
|
|
if methods := acceptableMethods.lookup(currency.NewCode("UST")); len(methods) == 0 {
|
|
t.Error("USDT should have many available methods")
|
|
}
|
|
if methods := acceptableMethods.lookup(currency.NewCode("ASdasdasdasd")); len(methods) != 0 {
|
|
t.Error("non-existent code should return no methods")
|
|
}
|
|
// since we're already loaded, this will return nil
|
|
if err := b.PopulateAcceptableMethods(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestGetAvailableTransferChains(t *testing.T) {
|
|
t.Parallel()
|
|
r, err := b.GetAvailableTransferChains(context.Background(), currency.USDT)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(r) < 2 {
|
|
t.Error("there should be many available USDT transfer chains")
|
|
}
|
|
}
|
|
|
|
func TestAccetableMethodStore(t *testing.T) {
|
|
t.Parallel()
|
|
var a acceptableMethodStore
|
|
if a.loaded() {
|
|
t.Error("should be empty")
|
|
}
|
|
data := map[string][]string{
|
|
"BITCOIN": {"BTC"},
|
|
"TETHER1": {"UST"},
|
|
"TETHER2": {"UST"},
|
|
}
|
|
a.load(data)
|
|
if !a.loaded() {
|
|
t.Error("data should be loaded")
|
|
}
|
|
if name := a.lookup(currency.NewCode("BTC")); len(name) != 1 && name[1] != "BITCOIN" {
|
|
t.Error("incorrect values")
|
|
}
|
|
if name := a.lookup(currency.NewCode("UST")); (name[0] != "TETHER1" && name[1] != "TETHER2") &&
|
|
(name[0] != "TETHER2" && name[1] != "TETHER1") {
|
|
t.Errorf("incorrect values")
|
|
}
|
|
if name := a.lookup(currency.NewCode("PANDA_HORSE")); len(name) != 0 {
|
|
t.Error("incorrect values")
|
|
}
|
|
}
|
|
|
|
func TestGetSiteListConfigData(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := b.GetSiteListConfigData(context.Background(), "")
|
|
if !errors.Is(err, errSetCannotBeEmpty) {
|
|
t.Fatalf("received: %v, expected: %v", err, errSetCannotBeEmpty)
|
|
}
|
|
|
|
pairs, err := b.GetSiteListConfigData(context.Background(), bitfinexSecuritiesPairs)
|
|
if !errors.Is(err, nil) {
|
|
t.Fatalf("received: %v, expected: %v", err, nil)
|
|
}
|
|
|
|
if len(pairs) == 0 {
|
|
t.Fatal("expected pairs")
|
|
}
|
|
}
|
|
|
|
func TestGetSiteInfoConfigData(t *testing.T) {
|
|
t.Parallel()
|
|
for _, assetType := range []asset.Item{asset.Spot, asset.Futures} {
|
|
pairs, err := b.GetSiteInfoConfigData(context.Background(), assetType)
|
|
if !errors.Is(err, nil) {
|
|
t.Errorf("Error from GetSiteInfoConfigData for %s type received: %v, expected: %v", assetType, err, nil)
|
|
}
|
|
if len(pairs) == 0 {
|
|
t.Errorf("GetSiteInfoConfigData returned no pairs for %s", assetType)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestOrderUpdate(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
_, err := b.OrderUpdate(context.Background(), "1234", "", "", 1, 1, 1)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestGetInactiveOrders(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
|
|
_, err := b.GetInactiveOrders(context.Background(), "tBTCUSD")
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
_, err = b.GetInactiveOrders(context.Background(), "tBTCUSD", 1, 2, 3, 4)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestCancelMultipleOrdersV2(t *testing.T) {
|
|
t.Parallel()
|
|
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
|
|
_, err := b.CancelMultipleOrdersV2(context.Background(), 1337, 0, 0, time.Time{}, false)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
// TestGetErrResp unit tests the helper func getErrResp
|
|
func TestGetErrResp(t *testing.T) {
|
|
t.Parallel()
|
|
fixture, err := os.Open("testdata/getErrResp.json")
|
|
if !assert.NoError(t, err, "Opening fixture should not error") {
|
|
t.FailNow()
|
|
}
|
|
s := bufio.NewScanner(fixture)
|
|
seen := 0
|
|
for s.Scan() {
|
|
testErr := b.getErrResp(s.Bytes())
|
|
seen++
|
|
switch seen {
|
|
case 1: // no event
|
|
assert.ErrorIs(t, testErr, errParsingWSField, "Message with no event Should get correct error type")
|
|
assert.ErrorContains(t, testErr, "'event'", "Message with no event error should contain missing field name")
|
|
assert.ErrorContains(t, testErr, "nightjar", "Message with no event error should contain the message")
|
|
case 2: // with {} for event
|
|
assert.NoError(t, testErr, "Message with '{}' for event field should not error")
|
|
case 3: // event != 'error'
|
|
assert.NoError(t, testErr, "Message with non-'error' event field should not error")
|
|
case 4: // event="error"
|
|
assert.ErrorIs(t, testErr, errUnknownError, "error without a message should throw unknown error")
|
|
assert.ErrorContains(t, testErr, "code: 0", "error without a code should throw code 0")
|
|
case 5: // Fully formatted
|
|
assert.ErrorContains(t, testErr, "redcoats", "message field should be in the error")
|
|
assert.ErrorContains(t, testErr, "code: 42", "code field should be in the error")
|
|
}
|
|
}
|
|
assert.NoError(t, s.Err(), "Fixture Scanner should not error")
|
|
assert.NoError(t, fixture.Close(), "Closing the fixture file should not error")
|
|
}
|
|
|
|
// setupWs is a helper function to connect both auth and normal websockets
|
|
// It will skip the test if websockets are not enabled
|
|
// It's up to the test to skip if it requires creds, though
|
|
func setupWs(tb testing.TB) {
|
|
tb.Helper()
|
|
if !b.Websocket.IsEnabled() {
|
|
tb.Skip("Websocket not enabled")
|
|
}
|
|
if b.Websocket.IsConnected() {
|
|
return
|
|
}
|
|
if wsConnected {
|
|
return
|
|
}
|
|
// We don't use b.websocket.Connect() because it'd subscribe to channels
|
|
err := b.WsConnect()
|
|
if !assert.NoError(tb, err, "WsConnect should not error") {
|
|
tb.FailNow()
|
|
}
|
|
|
|
wsConnected = true
|
|
}
|