package gemini import ( "context" "errors" "net/url" "strings" "sync" "testing" "time" "github.com/gorilla/websocket" "github.com/thrasher-corp/gocryptotrader/common" "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/order" "github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues" "github.com/thrasher-corp/gocryptotrader/exchanges/stream" "github.com/thrasher-corp/gocryptotrader/portfolio/withdraw" ) // Please enter sandbox API keys & assigned roles for better testing procedures const ( apiKey = "" apiSecret = "" canManipulateRealOrders = false ) const testCurrency = "btcusd" var g Gemini func TestStart(t *testing.T) { t.Parallel() err := g.Start(context.Background(), nil) if !errors.Is(err, common.ErrNilPointer) { t.Fatalf("received: '%v' but expected: '%v'", err, common.ErrNilPointer) } var testWg sync.WaitGroup err = g.Start(context.Background(), &testWg) if err != nil { t.Fatal(err) } testWg.Wait() } func TestGetSymbols(t *testing.T) { t.Parallel() _, err := g.GetSymbols(context.Background()) if err != nil { t.Error("GetSymbols() error", err) } } func TestFetchTradablePairs(t *testing.T) { t.Parallel() pairs, err := g.FetchTradablePairs(context.Background(), asset.Spot) if err != nil { t.Fatal(err) } if !pairs.Contains(currency.NewPair(currency.STORJ, currency.USD), false) { t.Error("expected pair STORJ-USD") } if !pairs.Contains(currency.NewPair(currency.BTC, currency.USD), false) { t.Error("expected pair BTC-USD") } if !pairs.Contains(currency.NewPair(currency.AAVE, currency.USD), false) { t.Error("expected pair AAVE-BTC") } } func TestGetTicker(t *testing.T) { t.Parallel() _, err := g.GetTicker(context.Background(), "BTCUSD") if err != nil { t.Error("GetTicker() error", err) } _, err = g.GetTicker(context.Background(), "bla") if err == nil { t.Error("GetTicker() Expected error") } } func TestGetOrderbook(t *testing.T) { t.Parallel() _, err := g.GetOrderbook(context.Background(), testCurrency, url.Values{}) if err != nil { t.Error("GetOrderbook() error", err) } } func TestGetTrades(t *testing.T) { t.Parallel() _, err := g.GetTrades(context.Background(), testCurrency, 0, 0, false) if err != nil { t.Error("GetTrades() error", err) } } func TestGetNotionalVolume(t *testing.T) { t.Parallel() _, err := g.GetNotionalVolume(context.Background()) if err != nil && mockTests { t.Error("GetNotionalVolume() error", err) } else if err == nil && !mockTests { t.Error("GetNotionalVolume() error cannot be nil") } } func TestGetAuction(t *testing.T) { t.Parallel() _, err := g.GetAuction(context.Background(), testCurrency) if err != nil { t.Error("GetAuction() error", err) } } func TestGetAuctionHistory(t *testing.T) { t.Parallel() _, err := g.GetAuctionHistory(context.Background(), testCurrency, url.Values{}) if err != nil { t.Error("GetAuctionHistory() error", err) } } func TestNewOrder(t *testing.T) { t.Parallel() _, err := g.NewOrder(context.Background(), testCurrency, 1, 9000000, order.Sell.Lower(), "exchange limit") if err != nil && mockTests { t.Error("NewOrder() error", err) } else if err == nil && !mockTests { t.Error("NewOrder() error cannot be nil") } } func TestCancelExistingOrder(t *testing.T) { t.Parallel() _, err := g.CancelExistingOrder(context.Background(), 265555413) if err != nil && mockTests { t.Error("CancelExistingOrder() error", err) } else if err == nil && !mockTests { t.Error("CancelExistingOrder() error cannot be nil") } } func TestCancelExistingOrders(t *testing.T) { t.Parallel() _, err := g.CancelExistingOrders(context.Background(), false) if err != nil && mockTests { t.Error("CancelExistingOrders() error", err) } else if err == nil && !mockTests { t.Error("CancelExistingOrders() error cannot be nil") } } func TestGetOrderStatus(t *testing.T) { t.Parallel() _, err := g.GetOrderStatus(context.Background(), 265563260) if err != nil && mockTests { t.Error("GetOrderStatus() error", err) } else if err == nil && !mockTests { t.Error("GetOrderStatus() error cannot be nil") } } func TestGetOrders(t *testing.T) { t.Parallel() _, err := g.GetOrders(context.Background()) if err != nil && mockTests { t.Error("GetOrders() error", err) } else if err == nil && !mockTests { t.Error("GetOrders() error cannot be nil") } } func TestGetTradeHistory(t *testing.T) { t.Parallel() _, err := g.GetTradeHistory(context.Background(), testCurrency, 0) if err != nil && mockTests { t.Error("GetTradeHistory() error", err) } else if err == nil && !mockTests { t.Error("GetTradeHistory() error cannot be nil") } } func TestGetTradeVolume(t *testing.T) { t.Parallel() _, err := g.GetTradeVolume(context.Background()) if err != nil && mockTests { t.Error("GetTradeVolume() error", err) } else if err == nil && !mockTests { t.Error("GetTradeVolume() error cannot be nil") } } func TestGetBalances(t *testing.T) { t.Parallel() _, err := g.GetBalances(context.Background()) if err != nil && mockTests { t.Error("GetBalances() error", err) } else if err == nil && !mockTests { t.Error("GetBalances() error cannot be nil") } } func TestGetCryptoDepositAddress(t *testing.T) { t.Parallel() _, err := g.GetCryptoDepositAddress(context.Background(), "LOL123", "btc") if err == nil { t.Error("GetCryptoDepositAddress() Expected error") } } func TestWithdrawCrypto(t *testing.T) { t.Parallel() _, err := g.WithdrawCrypto(context.Background(), "LOL123", "btc", 1) if err == nil { t.Error("WithdrawCrypto() Expected error") } } func TestPostHeartbeat(t *testing.T) { t.Parallel() _, err := g.PostHeartbeat(context.Background()) if err != nil && mockTests { t.Error("PostHeartbeat() error", err) } else if err == nil && !mockTests { t.Error("PostHeartbeat() error cannot be nil") } } func setFeeBuilder() *exchange.FeeBuilder { return &exchange.FeeBuilder{ Amount: 1, FeeType: exchange.CryptocurrencyTradeFee, Pair: currency.NewPairWithDelimiter(currency.BTC.String(), currency.LTC.String(), "_"), PurchasePrice: 1, FiatCurrency: currency.USD, BankTransactionType: exchange.WireTransfer, } } // TestGetFeeByTypeOfflineTradeFee logic test func TestGetFeeByTypeOfflineTradeFee(t *testing.T) { t.Parallel() var feeBuilder = setFeeBuilder() _, err := g.GetFeeByType(context.Background(), feeBuilder) if err != nil { t.Fatal(err) } if !areTestAPIKeysSet() { 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) { t.Parallel() var feeBuilder = setFeeBuilder() if areTestAPIKeysSet() || mockTests { // CryptocurrencyTradeFee Basic if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyTradeFee High quantity feeBuilder = setFeeBuilder() feeBuilder.Amount = 1000 feeBuilder.PurchasePrice = 1000 if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyTradeFee IsMaker feeBuilder = setFeeBuilder() feeBuilder.IsMaker = true if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyTradeFee Negative purchase price feeBuilder = setFeeBuilder() feeBuilder.PurchasePrice = -1000 if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } } // CryptocurrencyWithdrawalFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyWithdrawalFee Invalid currency feeBuilder = setFeeBuilder() feeBuilder.Pair.Base = currency.NewCode("hello") feeBuilder.FeeType = exchange.CryptocurrencyWithdrawalFee if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // CryptocurrencyDepositFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.CryptocurrencyDepositFee if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // InternationalBankDepositFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.InternationalBankDepositFee if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } // InternationalBankWithdrawalFee Basic feeBuilder = setFeeBuilder() feeBuilder.FeeType = exchange.InternationalBankWithdrawalFee feeBuilder.FiatCurrency = currency.USD if _, err := g.GetFee(context.Background(), feeBuilder); err != nil { t.Error(err) } } func TestFormatWithdrawPermissions(t *testing.T) { t.Parallel() expectedResult := exchange.AutoWithdrawCryptoWithAPIPermissionText + " & " + exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText withdrawPermissions := g.FormatWithdrawPermissions() if withdrawPermissions != expectedResult { t.Errorf("Expected: %s, Received: %s", expectedResult, withdrawPermissions) } } func TestGetActiveOrders(t *testing.T) { t.Parallel() var getOrdersRequest = order.GetOrdersRequest{ Type: order.AnyType, Pairs: []currency.Pair{ currency.NewPair(currency.LTC, currency.BTC), }, AssetType: asset.Spot, Side: order.AnySide, } _, err := g.GetActiveOrders(context.Background(), &getOrdersRequest) switch { case areTestAPIKeysSet() && err != nil && !mockTests: t.Errorf("Could not get open orders: %s", err) case !areTestAPIKeysSet() && err == nil && !mockTests: t.Error("Expecting an error when no keys are set") case mockTests && err != nil: t.Errorf("Could not get open orders: %s", err) } } func TestGetOrderHistory(t *testing.T) { t.Parallel() var getOrdersRequest = order.GetOrdersRequest{ Type: order.AnyType, Pairs: []currency.Pair{currency.NewPair(currency.LTC, currency.BTC)}, AssetType: asset.Spot, Side: order.AnySide, } _, err := g.GetOrderHistory(context.Background(), &getOrdersRequest) switch { case areTestAPIKeysSet() && err != nil: t.Errorf("Could not get order history: %s", err) case !areTestAPIKeysSet() && err == nil && !mockTests: t.Error("Expecting an error when no keys are set") case err != nil && mockTests: t.Errorf("Could not get order history: %s", err) } } // Any tests below this line have the ability to impact your orders on the exchange. Enable canManipulateRealOrders to run them // ---------------------------------------------------------------------------------------------------------------------------- func areTestAPIKeysSet() bool { return g.ValidateAPICredentials(g.GetDefaultCredentials()) == nil } func TestSubmitOrder(t *testing.T) { t.Parallel() if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var orderSubmission = &order.Submit{ Exchange: g.Name, Pair: currency.Pair{ Delimiter: "_", Base: currency.LTC, Quote: currency.BTC, }, Side: order.Buy, Type: order.Limit, Price: 10, Amount: 1, ClientID: "1234234", AssetType: asset.Spot, } response, err := g.SubmitOrder(context.Background(), orderSubmission) switch { case areTestAPIKeysSet() && (err != nil || response.Status != order.New): t.Errorf("Order failed to be placed: %v", err) case !areTestAPIKeysSet() && err == nil && !mockTests: t.Error("Expecting an error when no keys are set") case mockTests && err != nil: t.Errorf("Order failed to be placed: %v", err) } } func TestCancelExchangeOrder(t *testing.T) { t.Parallel() if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var orderCancellation = &order.Cancel{ OrderID: "266029865", AssetType: asset.Spot, Pair: currency.NewPair(currency.BTC, currency.USDT), } err := g.CancelOrder(context.Background(), orderCancellation) switch { case !areTestAPIKeysSet() && err == nil && !mockTests: t.Error("Expecting an error when no keys are set") case areTestAPIKeysSet() && err != nil: t.Errorf("Could not cancel orders: %v", err) case err != nil && mockTests: t.Errorf("Could not cancel orders: %v", err) } } func TestCancelAllExchangeOrders(t *testing.T) { t.Parallel() if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } 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 := g.CancelAllOrders(context.Background(), orderCancellation) switch { case !areTestAPIKeysSet() && err == nil && !mockTests: t.Error("Expecting an error when no keys are set") case areTestAPIKeysSet() && err != nil: t.Errorf("Could not cancel orders: %v", err) case mockTests && 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() _, err := g.ModifyOrder(context.Background(), &order.Modify{AssetType: asset.Spot}) if err == nil { t.Error("ModifyOrder() Expected error") } } func TestWithdraw(t *testing.T) { t.Parallel() withdrawCryptoRequest := withdraw.Request{ Exchange: g.Name, Amount: -1, Currency: currency.BTC, Description: "WITHDRAW IT ALL", Crypto: withdraw.CryptoRequest{ Address: core.BitcoinDonationAddress, }, } if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } _, err := g.WithdrawCryptocurrencyFunds(context.Background(), &withdrawCryptoRequest) if !areTestAPIKeysSet() && err == nil { t.Error("Expecting an error when no keys are set") } if areTestAPIKeysSet() && err != nil && !mockTests { t.Errorf("Withdraw failed to be placed: %v", err) } if areTestAPIKeysSet() && err == nil && mockTests { t.Errorf("Withdraw failed to be placed: %v", err) } } func TestWithdrawFiat(t *testing.T) { t.Parallel() if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var withdrawFiatRequest = withdraw.Request{} _, err := g.WithdrawFiatFunds(context.Background(), &withdrawFiatRequest) if err != common.ErrFunctionNotSupported { t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) } } func TestWithdrawInternationalBank(t *testing.T) { t.Parallel() if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests { t.Skip("API keys set, canManipulateRealOrders false, skipping test") } var withdrawFiatRequest = withdraw.Request{} _, err := g.WithdrawFiatFundsToInternationalBank(context.Background(), &withdrawFiatRequest) if err != common.ErrFunctionNotSupported { t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err) } } func TestGetDepositAddress(t *testing.T) { t.Parallel() _, err := g.GetDepositAddress(context.Background(), currency.BTC, "", "") if err == nil { t.Error("GetDepositAddress error cannot be nil") } } // TestWsAuth dials websocket, sends login request. func TestWsAuth(t *testing.T) { t.Parallel() err := g.API.Endpoints.SetRunning(exchange.WebsocketSpot.String(), geminiWebsocketSandboxEndpoint) if err != nil { t.Error(err) } if !g.Websocket.IsEnabled() && !g.API.AuthenticatedWebsocketSupport || !areTestAPIKeysSet() { t.Skip(stream.WebsocketNotEnabled) } var dialer websocket.Dialer go g.wsReadData() err = g.WsAuth(context.Background(), &dialer) if err != nil { t.Error(err) } timer := time.NewTimer(sharedtestvalues.WebsocketResponseDefaultTimeout) select { case resp := <-g.Websocket.DataHandler: subAck, ok := resp.(WsSubscriptionAcknowledgementResponse) if !ok { t.Error("unable to type assert WsSubscriptionAcknowledgementResponse") } if subAck.Type != "subscription_ack" { t.Error("Login failed") } case <-timer.C: t.Error("Expected response") } timer.Stop() } func TestWsMissingRole(t *testing.T) { pressXToJSON := []byte(`{ "result":"error", "reason":"MissingRole", "message":"To access this endpoint, you need to log in to the website and go to the settings page to assign one of these roles [FundManager] to API key wujB3szN54gtJ4QDhqRJ which currently has roles [Trader]" }`) if err := g.wsHandleData(pressXToJSON); err == nil { t.Error("Expected error") } } func TestWsOrderEventSubscriptionResponse(t *testing.T) { pressXToJSON := []byte(`[ { "type" : "accepted", "order_id" : "372456298", "event_id" : "372456299", "client_order_id": "20170208_example", "api_session" : "AeRLptFXoYEqLaNiRwv8", "symbol" : "btcusd", "side" : "buy", "order_type" : "exchange limit", "timestamp" : "1478203017", "timestampms" : 1478203017455, "is_live" : true, "is_cancelled" : false, "is_hidden" : false, "avg_execution_price" : "0", "original_amount" : "14.0296", "price" : "1059.54" } ]`) err := g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[{ "type": "accepted", "order_id": "109535951", "event_id": "109535952", "api_session": "UI", "symbol": "btcusd", "side": "buy", "order_type": "exchange limit", "timestamp": "1547742904", "timestampms": 1547742904989, "is_live": true, "is_cancelled": false, "is_hidden": false, "original_amount": "1", "price": "3592.00", "socket_sequence": 13 }]`) err = g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[{ "type": "accepted", "order_id": "109964529", "event_id": "109964530", "api_session": "UI", "symbol": "btcusd", "side": "buy", "order_type": "market buy", "timestamp": "1547756076", "timestampms": 1547756076644, "is_live": false, "is_cancelled": false, "is_hidden": false, "total_spend": "200.00", "socket_sequence": 29 }]`) err = g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[{ "type": "accepted", "order_id": "109964616", "event_id": "109964617", "api_session": "UI", "symbol": "btcusd", "side": "sell", "order_type": "market sell", "timestamp": "1547756893", "timestampms": 1547756893937, "is_live": true, "is_cancelled": false, "is_hidden": false, "original_amount": "25", "socket_sequence": 26 }]`) err = g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`[ { "type" : "accepted", "order_id" : "6321", "event_id" : "6322", "api_session" : "UI", "symbol" : "btcusd", "side" : "sell", "order_type" : "block_trade", "timestamp" : "1478204198", "timestampms" : 1478204198989, "is_live" : true, "is_cancelled" : false, "is_hidden" : true, "avg_execution_price" : "0", "original_amount" : "500", "socket_sequence" : 32307 } ]`) err = g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsSubAck(t *testing.T) { pressXToJSON := []byte(`{ "type": "subscription_ack", "accountId": 5365, "subscriptionId": "ws-order-events-5365-b8bk32clqeb13g9tk8p0", "symbolFilter": [ "btcusd" ], "apiSessionFilter": [ "UI" ], "eventTypeFilter": [ "fill", "closed" ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsHeartbeat(t *testing.T) { pressXToJSON := []byte(`{ "type": "heartbeat", "timestampms": 1547742998508, "sequence": 31, "trace_id": "b8biknoqppr32kc7gfgg", "socket_sequence": 37 }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsUnsubscribe(t *testing.T) { pressXToJSON := []byte(`{ "type": "unsubscribe", "subscriptions": [{ "name": "l2", "symbols": [ "BTCUSD", "ETHBTC" ]}, {"name": "candles_1m", "symbols": [ "BTCUSD", "ETHBTC" ]} ] }`) err := g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsTradeData(t *testing.T) { pressXToJSON := []byte(`{ "type": "update", "eventId": 5375547515, "timestamp": 1547760288, "timestampms": 1547760288001, "socket_sequence": 15, "events": [ { "type": "trade", "tid": 5375547515, "price": "3632.54", "amount": "0.1362819142", "makerSide": "ask" } ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsAuctionData(t *testing.T) { pressXToJSON := []byte(`{ "eventId": 371469414, "socket_sequence":4009, "timestamp":1486501200, "timestampms":1486501200000, "events": [ { "amount": "1406", "makerSide": "auction", "price": "1048.75", "tid": 371469414, "type": "trade" }, { "auction_price": "1048.75", "auction_quantity": "1406", "eid": 371469414, "highest_bid_price": "1050.98", "lowest_ask_price": "1050.99", "result": "success", "time_ms": 1486501200000, "type": "auction_result" } ], "type": "update" }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsBlockTrade(t *testing.T) { pressXToJSON := []byte(`{ "type":"update", "eventId":1111597035, "socket_sequence":8, "timestamp":1501175027, "timestampms":1501175027304, "events":[ { "type":"block_trade", "tid":1111597035, "price":"10100.00", "amount":"1000" } ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWSTrade(t *testing.T) { pressXToJSON := []byte(`{ "type": "trade", "symbol": "BTCUSD", "event_id": 3575573053, "timestamp": 151231241, "price": "9004.21000000", "quantity": "0.09110000", "side": "buy" }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsCandles(t *testing.T) { pressXToJSON := []byte(`{ "type": "candles_15m_updates", "symbol": "BTCUSD", "changes": [ [ 1561054500000, 9350.18, 9358.35, 9350.18, 9355.51, 2.07 ], [ 1561053600000, 9357.33, 9357.33, 9350.18, 9350.18, 1.5900161 ] ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsAuctions(t *testing.T) { pressXToJSON := []byte(`{ "eventId": 372481811, "socket_sequence":23, "timestamp": 1486591200, "timestampms": 1486591200000, "events": [ { "auction_open_ms": 1486591200000, "auction_time_ms": 1486674000000, "first_indicative_ms": 1486673400000, "last_cancel_time_ms": 1486673985000, "type": "auction_open" } ], "type": "update" }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } pressXToJSON = []byte(`{ "type": "update", "eventId": 2248762586, "timestamp": 1510865640, "timestampms": 1510865640122, "socket_sequence": 177, "events": [ { "type": "auction_indicative", "eid": 2248762586, "result": "success", "time_ms": 1510865640000, "highest_bid_price": "7730.69", "lowest_ask_price": "7730.7", "collar_price": "7730.695", "indicative_price": "7750", "indicative_quantity": "45.43325086" } ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } pressXToJSON = []byte(`{ "type": "update", "eventId": 2248795680, "timestamp": 1510866000, "timestampms": 1510866000095, "socket_sequence": 2920, "events": [ { "type": "trade", "tid": 2248795680, "price": "7763.23", "amount": "55.95", "makerSide": "auction" }, { "type": "auction_result", "eid": 2248795680, "result": "success", "time_ms": 1510866000000, "highest_bid_price": "7769", "lowest_ask_price": "7769.01", "collar_price": "7769.005", "auction_price": "7763.23", "auction_quantity": "55.95" } ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestWsMarketData(t *testing.T) { pressXToJSON := []byte(`{ "type": "update", "eventId": 5375461993, "socket_sequence": 0, "events": [ { "type": "change", "reason": "initial", "price": "3641.61", "delta": "0.83372051", "remaining": "0.83372051", "side": "bid" }, { "type": "change", "reason": "initial", "price": "3641.62", "delta": "4.072", "remaining": "4.072", "side": "ask" } ] } `) err := g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`{ "type": "update", "eventId": 5375461993, "socket_sequence": 0, "events": [ { "type": "change", "reason": "initial", "price": "3641.61", "delta": "0.83372051", "remaining": "0.83372051", "side": "bid" }, { "type": "change", "reason": "initial", "price": "3641.62", "delta": "4.072", "remaining": "4.072", "side": "ask" } ] } `) err = g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } pressXToJSON = []byte(`{ "type": "update", "eventId": 5375503736, "timestamp": 1547759964, "timestampms": 1547759964051, "socket_sequence": 2, "events": [ { "type": "change", "side": "bid", "price": "3628.01", "remaining": "0", "delta": "-2", "reason": "cancel" } ] } `) err = g.wsHandleData(pressXToJSON) if err != nil { t.Error(err) } } func TestWsError(t *testing.T) { tt := []struct { Data []byte ErrorExpected bool ErrorShouldContain string }{ { Data: []byte(`{"type": "test"}`), ErrorExpected: false, }, { Data: []byte(`{"result": "bla"}`), ErrorExpected: false, }, { Data: []byte(`{"result": "error"}`), ErrorExpected: true, ErrorShouldContain: "Unhandled websocket error", }, { Data: []byte(`{"result": "error","reason": "InvalidJson"}`), ErrorExpected: true, ErrorShouldContain: "InvalidJson", }, { Data: []byte(`{"result": "error","reason": "InvalidJson", "message": "WeAreGoingToTheMoonKirby"}`), ErrorExpected: true, ErrorShouldContain: "InvalidJson - WeAreGoingToTheMoonKirby", }, } for x := range tt { err := g.wsHandleData(tt[x].Data) if tt[x].ErrorExpected && err != nil && !strings.Contains(err.Error(), tt[x].ErrorShouldContain) { t.Errorf("expected error to contain: %s, got: %s", tt[x].ErrorShouldContain, err.Error(), ) } else if !tt[x].ErrorExpected && err != nil { t.Errorf("unexpected error: %s", err) } } } func TestWsLevel2Update(t *testing.T) { pressXToJSON := []byte(`{ "type": "l2_updates", "symbol": "BTCUSD", "changes": [ [ "buy", "9122.04", "0.00121425" ], [ "sell", "9122.07", "0.98942292" ] ], "trades": [{ "type": "trade", "symbol": "BTCUSD", "event_id": 169841458, "timestamp": 1560976400428, "price": "9122.04", "quantity": "0.0073173", "side": "sell" }], "auction_events": [{ "type": "auction_result", "symbol": "BTCUSD", "time_ms": 1560974400000, "result": "success", "highest_bid_price": "9150.80", "lowest_ask_price": "9150.81", "collar_price": "9146.93", "auction_price": "9145.00", "auction_quantity": "470.10390845" }, { "type": "auction_indicative", "symbol": "BTCUSD", "time_ms": 1560974385000, "result": "success", "highest_bid_price": "9150.80", "lowest_ask_price": "9150.81", "collar_price": "9146.84", "auction_price": "9134.04", "auction_quantity": "389.3094317" } ] }`) if err := g.wsHandleData(pressXToJSON); err != nil { t.Error(err) } } func TestResponseToStatus(t *testing.T) { type TestCases struct { Case string Result order.Status } testCases := []TestCases{ {Case: "accepted", Result: order.New}, {Case: "booked", Result: order.Active}, {Case: "fill", Result: order.Filled}, {Case: "cancelled", Result: order.Cancelled}, {Case: "cancel_rejected", Result: order.Rejected}, {Case: "closed", Result: order.Filled}, {Case: "LOL", Result: order.UnknownStatus}, } for i := range testCases { result, _ := stringToOrderStatus(testCases[i].Case) if result != testCases[i].Result { t.Errorf("Expected: %v, received: %v", testCases[i].Result, result) } } } func TestResponseToOrderType(t *testing.T) { type TestCases struct { Case string Result order.Type } testCases := []TestCases{ {Case: "exchange limit", Result: order.Limit}, {Case: "auction-only limit", Result: order.Limit}, {Case: "indication-of-interest limit", Result: order.Limit}, {Case: "market buy", Result: order.Market}, {Case: "market sell", Result: order.Market}, {Case: "block_trade", Result: order.Market}, {Case: "LOL", Result: order.UnknownType}, } for i := range testCases { result, _ := stringToOrderType(testCases[i].Case) if result != testCases[i].Result { t.Errorf("Expected: %v, received: %v", testCases[i].Result, result) } } } func TestGetRecentTrades(t *testing.T) { t.Parallel() currencyPair, err := currency.NewPairFromString(testCurrency) if err != nil { t.Fatal(err) } _, err = g.GetRecentTrades(context.Background(), currencyPair, asset.Spot) if err != nil { t.Error(err) } } func TestGetHistoricTrades(t *testing.T) { t.Parallel() currencyPair, err := currency.NewPairFromString(testCurrency) if err != nil { t.Fatal(err) } tStart := time.Date(2020, 6, 6, 0, 0, 0, 0, time.UTC) tEnd := time.Date(2020, 6, 7, 0, 0, 0, 0, time.UTC) if !mockTests { tStart = time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 0, 0, 0, time.UTC) tEnd = time.Date(time.Now().Year(), time.Now().Month(), 1, 0, 15, 0, 0, time.UTC) } _, err = g.GetHistoricTrades(context.Background(), currencyPair, asset.Spot, tStart, tEnd) if err != nil { t.Error(err) } }