Skip to content

Commit

Permalink
Bitfinex: TestWsSubscribe and various fixes
Browse files Browse the repository at this point in the history
* Enables the websocket for live non-authed integration tests by default
* Adds an integration test for subscriptions
* Changes the Ws tests to respect canManipulateRealOrders
* Uses WsConnect instead of setupWs; fixes seqNo config not sent for WS tests
* Allows api creds to live in config/testdata.json which might be
  less likely to accidentally commit, and less obtrusive
  • Loading branch information
gbjk committed Sep 24, 2023
1 parent 838b59c commit 82f77de
Showing 1 changed file with 90 additions and 92 deletions.
182 changes: 90 additions & 92 deletions exchanges/bitfinex/bitfinex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import (
"context"
"errors"
"log"
"net/http"
"os"
"sync"
"testing"
"time"

"github.com/buger/jsonparser"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
Expand All @@ -28,15 +26,15 @@ import (
"github.com/thrasher-corp/gocryptotrader/portfolio/withdraw"
)

// Please supply your own keys here to do better tests
// Please supply API keys here or in config/testdata.json to test authenticated endpoints
const (
apiKey = ""
apiSecret = ""
canManipulateRealOrders = false
)

var b = &Bitfinex{}
var wsAuthExecuted bool
var wsConnected bool
var btcusdPair currency.Pair

func TestMain(m *testing.M) {
Expand All @@ -55,7 +53,9 @@ func TestMain(m *testing.M) {
if err != nil {
log.Fatal("Bitfinex setup error", err)
}
b.SetCredentials(apiKey, apiSecret, "", "", "", "")
if apiKey != "" {
b.SetCredentials(apiKey, apiSecret, "", "", "", "")
}
if !b.Enabled || len(b.BaseCurrencies) < 1 {
log.Fatal("Bitfinex Setup values not set correctly")
}
Expand Down Expand Up @@ -861,9 +861,9 @@ func TestGetOrderHistory(t *testing.T) {
}
}

// Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
// Start RealTests
// Any tests in this section 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)
Expand Down Expand Up @@ -916,7 +916,7 @@ func TestCancelExchangeOrder(t *testing.T) {
}
}

func TestCancelAllExchangeOrdera(t *testing.T) {
func TestCancelAllExchangeOrders(t *testing.T) {
t.Parallel()
sharedtestvalues.SkipTestIfCannotManipulateOrders(t, b, canManipulateRealOrders)

Expand Down Expand Up @@ -1051,56 +1051,58 @@ func TestGetDepositAddress(t *testing.T) {
}
}

func setupWs() {
var dialer websocket.Dialer
err := b.Websocket.AuthConn.Dial(&dialer, http.Header{})
if err != nil {
log.Fatal(err)
}
go b.wsReadData(b.Websocket.AuthConn)
go b.WsDataHandler()
}
// ----------------------------------------------------------------------------------------------------------------------------
// End RealTests

// TestWs tests have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them
// ----------------------------------------------------------------------------------------------------------------------------
// TestWsAuth dials websocket, sends login request.
func TestWsAuth(t *testing.T) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
runAuth(t)
}

//nolint:gocritic // Only used as a testing helper function in this package
func runAuth(t *testing.T) {
t.Helper()
setupWs()
if err := b.WsSendAuth(context.Background()); err != nil {
t.Error(err)
if !b.Websocket.IsEnabled() {
t.Skip(stream.WebsocketNotEnabled)
}
timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout)
select {
case resp := <-b.Websocket.DataHandler:
if logResponse, ok := resp.(map[string]interface{}); ok {
if logResponse["event"] != "auth" && logResponse["status"] != "OK" {
t.Error("expected successful login")
}
} else {
t.Error("Unexpected response")
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")

// An upcoming PR may change this to a specific datatype
var resp map[string]interface{}
catcher := func() (ok bool) {
select {
case v := <-b.Websocket.DataHandler:
resp, ok = v.(map[string]interface{})
default:
}
case <-timer.C:
t.Error("Have not received a response")
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")
}
timer.Stop()
wsAuthExecuted = true
}

// TestWsSubscribe tests Subscribe and Unsubscribe functionality
func TestWsSubscribe(t *testing.T) {
setupWs(t)
defSubs, err := b.GenerateDefaultSubscriptions()
assert.NoError(t, err)
err = b.Subscribe([]stream.ChannelSubscription{defSubs[0]})
assert.NoError(t, err)
s, err := b.GetSubscriptions()
assert.NoError(t, err)
err = b.Unsubscribe(s)
assert.NoError(t, err)
}

// TestWsPlaceOrder dials websocket, sends order request.
func TestWsPlaceOrder(t *testing.T) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(t)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
setupWs(t)

_, err := b.WsNewOrder(&WsNewOrderRequest{
GroupID: 1,
Expand All @@ -1116,25 +1118,17 @@ func TestWsPlaceOrder(t *testing.T) {

// TestWsCancelOrder dials websocket, sends cancel request.
func TestWsCancelOrder(t *testing.T) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(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) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(t)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
setupWs(t)
err := b.WsModifyOrder(&WsUpdateOrderRequest{
OrderID: 1234,
Price: -111,
Expand All @@ -1147,25 +1141,17 @@ func TestWsUpdateOrder(t *testing.T) {

// TestWsCancelAllOrders dials websocket, sends cancel all request.
func TestWsCancelAllOrders(t *testing.T) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(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) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(t)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
setupWs(t)
err := b.WsCancelMultiOrders([]int64{1, 2, 3, 4})
if err != nil {
t.Error(err)
Expand All @@ -1174,12 +1160,8 @@ func TestWsCancelMultiOrders(t *testing.T) {

// TestWsNewOffer dials websocket, sends new offer request.
func TestWsNewOffer(t *testing.T) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(t)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
setupWs(t)
err := b.WsNewOffer(&WsNewOfferRequest{
Type: order.Limit.String(),
Symbol: "fBTC",
Expand All @@ -1194,12 +1176,8 @@ func TestWsNewOffer(t *testing.T) {

// TestWsCancelOffer dials websocket, sends cancel offer request.
func TestWsCancelOffer(t *testing.T) {
if !b.Websocket.IsEnabled() && !b.API.AuthenticatedWebsocketSupport {
sharedtestvalues.SkipTestIfCredentialsUnset(t, b)
}
if !wsAuthExecuted {
runAuth(t)
}
sharedtestvalues.SkipTestIfCredentialsUnset(t, b, canManipulateRealOrders)
setupWs(t)
if err := b.WsCancelOffer(1234); err != nil {
t.Error(err)
}
Expand Down Expand Up @@ -1336,7 +1314,7 @@ func TestWsNotifications(t *testing.T) {
}
}

func TestWSFundingOfferSnapshotAndUpdate(t *testing.T) {
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)
Expand All @@ -1348,7 +1326,7 @@ func TestWSFundingOfferSnapshotAndUpdate(t *testing.T) {
}
}

func TestWSFundingCreditSnapshotAndUpdate(t *testing.T) {
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)
Expand All @@ -1360,7 +1338,7 @@ func TestWSFundingCreditSnapshotAndUpdate(t *testing.T) {
}
}

func TestWSFundingLoanSnapshotAndUpdate(t *testing.T) {
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)
Expand All @@ -1372,35 +1350,35 @@ func TestWSFundingLoanSnapshotAndUpdate(t *testing.T) {
}
}

func TestWSWalletSnapshot(t *testing.T) {
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) {
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) {
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) {
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) {
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)
Expand Down Expand Up @@ -1858,3 +1836,23 @@ func TestChanForSub(t *testing.T) {
assert.Nil(t, err, "No error returned when sub found")
assert.EqualValues(t, want, *s, "Correct Sub found")
}

// 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
}
wsConnected = true
// We don't use b.websocket.Connect() because it'd subscribe to channels
err := b.WsConnect()
assert.NoError(tb, err, "WsConnect should not error")
}

0 comments on commit 82f77de

Please sign in to comment.