mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-08 23:16:54 +00:00
Tests: Various race fixes and move TestFixtureToDataHandler (#1534)
* Tests: Move and simplify TestFixtureToDataHandler * Currency: Fix PairsManager.Load breaking matcher * Tests: Add multi-instance cache to UpdatePairsOnce * Kraken: Fix TestUpdateTickers race error Calling StorePairs on global instance can lead to race * Bitfinex: Fix TestUpdateTickers racing intermittently * Currency: Fix concurrent access to PM formats * Currency: Fix SupportsAsset implementation This should delegate entirely to PairManager's IsAssetSupported * Okx: Fix PM intrusion, rm GetPairFromInstrumentID * Exchange: Fix SetGlobalPairsManager to set asset enabled * Bitflyer: Fix race on set TestGetCurrURL TestGetCurrencyTradeURL would fail sometimes due to sequencing of enabling futures but not having pairs for it. * Tests: Simplify usage pattern for FixtureToDH
This commit is contained in:
@@ -3065,15 +3065,6 @@ func (ok *Okx) GetUnderlying(pair currency.Pair, a asset.Item) (string, error) {
|
||||
return pair.Base.String() + format.Delimiter + pair.Quote.String(), nil
|
||||
}
|
||||
|
||||
// GetPairFromInstrumentID returns a currency pair give an instrument ID and asset Item, which represents the instrument type.
|
||||
func (ok *Okx) GetPairFromInstrumentID(instrumentID string) (currency.Pair, error) {
|
||||
codes := strings.Split(instrumentID, ok.CurrencyPairs.RequestFormat.Delimiter)
|
||||
if len(codes) >= 2 {
|
||||
instrumentID = codes[0] + ok.CurrencyPairs.RequestFormat.Delimiter + strings.Join(codes[1:], ok.CurrencyPairs.RequestFormat.Delimiter)
|
||||
}
|
||||
return currency.NewPairFromString(instrumentID)
|
||||
}
|
||||
|
||||
// GetOrderBookDepth returns the recent order asks and bids before specified timestamp.
|
||||
func (ok *Okx) GetOrderBookDepth(ctx context.Context, instrumentID string, depth int64) (*OrderBookResponse, error) {
|
||||
params := url.Values{}
|
||||
@@ -4320,11 +4311,15 @@ func (ok *Okx) GetAssetsFromInstrumentTypeOrID(instType, instrumentID string) ([
|
||||
if instrumentID == "" {
|
||||
return nil, fmt.Errorf("%w instrumentID", errEmptyArgument)
|
||||
}
|
||||
splitSymbol := strings.Split(instrumentID, ok.CurrencyPairs.RequestFormat.Delimiter)
|
||||
pf, err := ok.CurrencyPairs.GetFormat(asset.Spot, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
splitSymbol := strings.Split(instrumentID, pf.Delimiter)
|
||||
if len(splitSymbol) <= 1 {
|
||||
return nil, fmt.Errorf("%w %v", currency.ErrCurrencyNotSupported, instrumentID)
|
||||
}
|
||||
pair, err := currency.NewPairDelimiter(instrumentID, ok.CurrencyPairs.RequestFormat.Delimiter)
|
||||
pair, err := currency.NewPairDelimiter(instrumentID, pf.Delimiter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -2206,24 +2206,6 @@ func TestWithdraw(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPairFromInstrumentID(t *testing.T) {
|
||||
t.Parallel()
|
||||
instruments := []string{
|
||||
"BTC-USDT",
|
||||
"BTC-USDT-SWAP",
|
||||
"BTC-USDT-ER33234",
|
||||
}
|
||||
if _, err := ok.GetPairFromInstrumentID(instruments[0]); err != nil {
|
||||
t.Error("Okx GetPairFromInstrumentID() error", err)
|
||||
}
|
||||
if _, ere := ok.GetPairFromInstrumentID(instruments[1]); ere != nil {
|
||||
t.Error("Okx GetPairFromInstrumentID() error", ere)
|
||||
}
|
||||
if _, erf := ok.GetPairFromInstrumentID(instruments[2]); erf != nil {
|
||||
t.Error("Okx GetPairFromInstrumentID() error", erf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetActiveOrders(t *testing.T) {
|
||||
t.Parallel()
|
||||
sharedtestvalues.SkipTestIfCredentialsUnset(t, ok)
|
||||
@@ -2534,68 +2516,63 @@ func TestBalanceAndPosition(t *testing.T) {
|
||||
|
||||
func TestOrderPushData(t *testing.T) {
|
||||
t.Parallel()
|
||||
n := new(Okx)
|
||||
sharedtestvalues.TestFixtureToDataHandler(t, ok, n, "testdata/wsOrders.json", n.WsHandleData)
|
||||
seen := 0
|
||||
for reading := true; reading; {
|
||||
select {
|
||||
default:
|
||||
reading = false
|
||||
case resp := <-n.GetBase().Websocket.DataHandler:
|
||||
seen++
|
||||
switch v := resp.(type) {
|
||||
case *order.Detail:
|
||||
switch seen {
|
||||
case 1:
|
||||
assert.Equal(t, "452197707845865472", v.OrderID, "OrderID")
|
||||
assert.Equal(t, "HamsterParty14", v.ClientOrderID, "ClientOrderID")
|
||||
assert.Equal(t, asset.Spot, v.AssetType, "AssetType")
|
||||
assert.Equal(t, order.Sell, v.Side, "Side")
|
||||
assert.Equal(t, order.Filled, v.Status, "Status")
|
||||
assert.Equal(t, order.Limit, v.Type, "Type")
|
||||
assert.Equal(t, currency.NewPairWithDelimiter("BTC", "USDT", "-"), v.Pair, "Pair")
|
||||
assert.Equal(t, 31527.1, v.AverageExecutedPrice, "AverageExecutedPrice")
|
||||
assert.Equal(t, time.UnixMilli(1654084334977), v.Date, "Date")
|
||||
assert.Equal(t, time.UnixMilli(1654084353263), v.CloseTime, "CloseTime")
|
||||
assert.Equal(t, 0.001, v.Amount, "Amount")
|
||||
assert.Equal(t, 0.001, v.ExecutedAmount, "ExecutedAmount")
|
||||
assert.Equal(t, 0.000, v.RemainingAmount, "RemainingAmount")
|
||||
assert.Equal(t, 31527.1, v.Price, "Price")
|
||||
assert.Equal(t, 0.02522168, v.Fee, "Fee")
|
||||
assert.Equal(t, currency.USDT, v.FeeAsset, "FeeAsset")
|
||||
case 2:
|
||||
assert.Equal(t, "620258920632008725", v.OrderID, "OrderID")
|
||||
assert.Equal(t, asset.Spot, v.AssetType, "AssetType")
|
||||
assert.Equal(t, order.Market, v.Type, "Type")
|
||||
assert.Equal(t, order.Sell, v.Side, "Side")
|
||||
assert.Equal(t, order.Active, v.Status, "Status")
|
||||
assert.Equal(t, 0.0, v.Amount, "Amount should be 0 for a market sell")
|
||||
assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount")
|
||||
case 3:
|
||||
assert.Equal(t, "620258920632008725", v.OrderID, "OrderID")
|
||||
assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount")
|
||||
assert.Equal(t, 0.00038127046945832905, v.Amount, "Amount")
|
||||
assert.Equal(t, 0.010000249968, v.Fee, "Fee")
|
||||
assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount")
|
||||
assert.Equal(t, 0.00038128, v.ExecutedAmount, "ExecutedAmount")
|
||||
assert.Equal(t, order.PartiallyFilled, v.Status, "Status")
|
||||
case 4:
|
||||
assert.Equal(t, "620258920632008725", v.OrderID, "OrderID")
|
||||
assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount")
|
||||
assert.Equal(t, 0.010000249968, v.Fee, "Fee")
|
||||
assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount")
|
||||
assert.Equal(t, 0.00038128, v.ExecutedAmount, "ExecutedAmount")
|
||||
assert.Equal(t, 0.00038128, v.Amount, "Amount should be derived because order filled")
|
||||
assert.Equal(t, order.Filled, v.Status, "Status")
|
||||
}
|
||||
case error:
|
||||
t.Error(v)
|
||||
default:
|
||||
t.Errorf("Got unexpected data: %T %v", v, v)
|
||||
ok := new(Okx) //nolint:govet // Intentional shadow to avoid future copy/paste mistakes
|
||||
require.NoError(t, testexch.Setup(ok), "Test instance Setup must not error")
|
||||
testexch.FixtureToDataHandler(t, "testdata/wsOrders.json", ok.WsHandleData)
|
||||
close(ok.Websocket.DataHandler)
|
||||
assert.Len(t, ok.Websocket.DataHandler, 4, "Should see 4 orders")
|
||||
for resp := range ok.Websocket.DataHandler {
|
||||
switch v := resp.(type) {
|
||||
case *order.Detail:
|
||||
switch len(ok.Websocket.DataHandler) {
|
||||
case 3:
|
||||
assert.Equal(t, "452197707845865472", v.OrderID, "OrderID")
|
||||
assert.Equal(t, "HamsterParty14", v.ClientOrderID, "ClientOrderID")
|
||||
assert.Equal(t, asset.Spot, v.AssetType, "AssetType")
|
||||
assert.Equal(t, order.Sell, v.Side, "Side")
|
||||
assert.Equal(t, order.Filled, v.Status, "Status")
|
||||
assert.Equal(t, order.Limit, v.Type, "Type")
|
||||
assert.Equal(t, currency.NewPairWithDelimiter("BTC", "USDT", "-"), v.Pair, "Pair")
|
||||
assert.Equal(t, 31527.1, v.AverageExecutedPrice, "AverageExecutedPrice")
|
||||
assert.Equal(t, time.UnixMilli(1654084334977), v.Date, "Date")
|
||||
assert.Equal(t, time.UnixMilli(1654084353263), v.CloseTime, "CloseTime")
|
||||
assert.Equal(t, 0.001, v.Amount, "Amount")
|
||||
assert.Equal(t, 0.001, v.ExecutedAmount, "ExecutedAmount")
|
||||
assert.Equal(t, 0.000, v.RemainingAmount, "RemainingAmount")
|
||||
assert.Equal(t, 31527.1, v.Price, "Price")
|
||||
assert.Equal(t, 0.02522168, v.Fee, "Fee")
|
||||
assert.Equal(t, currency.USDT, v.FeeAsset, "FeeAsset")
|
||||
case 2:
|
||||
assert.Equal(t, "620258920632008725", v.OrderID, "OrderID")
|
||||
assert.Equal(t, asset.Spot, v.AssetType, "AssetType")
|
||||
assert.Equal(t, order.Market, v.Type, "Type")
|
||||
assert.Equal(t, order.Sell, v.Side, "Side")
|
||||
assert.Equal(t, order.Active, v.Status, "Status")
|
||||
assert.Equal(t, 0.0, v.Amount, "Amount should be 0 for a market sell")
|
||||
assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount")
|
||||
case 1:
|
||||
assert.Equal(t, "620258920632008725", v.OrderID, "OrderID")
|
||||
assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount")
|
||||
assert.Equal(t, 0.00038127046945832905, v.Amount, "Amount")
|
||||
assert.Equal(t, 0.010000249968, v.Fee, "Fee")
|
||||
assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount")
|
||||
assert.Equal(t, 0.00038128, v.ExecutedAmount, "ExecutedAmount")
|
||||
assert.Equal(t, order.PartiallyFilled, v.Status, "Status")
|
||||
case 0:
|
||||
assert.Equal(t, "620258920632008725", v.OrderID, "OrderID")
|
||||
assert.Equal(t, 10.0, v.QuoteAmount, "QuoteAmount")
|
||||
assert.Equal(t, 0.010000249968, v.Fee, "Fee")
|
||||
assert.Equal(t, 0.0, v.RemainingAmount, "RemainingAmount")
|
||||
assert.Equal(t, 0.00038128, v.ExecutedAmount, "ExecutedAmount")
|
||||
assert.Equal(t, 0.00038128, v.Amount, "Amount should be derived because order filled")
|
||||
assert.Equal(t, order.Filled, v.Status, "Status")
|
||||
}
|
||||
case error:
|
||||
t.Error(v)
|
||||
default:
|
||||
t.Errorf("Got unexpected data: %T %v", v, v)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, 4, seen, "Saw 4 records")
|
||||
}
|
||||
|
||||
const algoOrdersPushDataJSON = `{"arg": {"channel": "orders-algo","uid": "77982378738415879","instType": "FUTURES","instId": "BTC-USD-200329"},"data": [{"instType": "FUTURES","instId": "BTC-USD-200329","ordId": "312269865356374016","ccy": "BTC","algoId": "1234","px": "999","sz": "3","tdMode": "cross","tgtCcy": "","notionalUsd": "","ordType": "trigger","side": "buy","posSide": "long","state": "live","lever": "20","tpTriggerPx": "","tpTriggerPxType": "","tpOrdPx": "","slTriggerPx": "","slTriggerPxType": "","triggerPx": "99","triggerPxType": "last","ordPx": "12","actualSz": "","actualPx": "","tag": "adadadadad","actualSide": "","triggerTime": "1597026383085","cTime": "1597026383000"}]}`
|
||||
|
||||
@@ -688,7 +688,8 @@ func (ok *Okx) wsProcessIndexCandles(respRaw []byte) error {
|
||||
if len(response.Data) == 0 {
|
||||
return errNoCandlestickDataFound
|
||||
}
|
||||
pair, err := ok.GetPairFromInstrumentID(response.Argument.InstrumentID)
|
||||
|
||||
pair, err := currency.NewPairFromString(response.Argument.InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -750,7 +751,7 @@ func (ok *Okx) wsProcessOrderbook5(data []byte) error {
|
||||
return err
|
||||
}
|
||||
|
||||
pair, err := ok.GetPairFromInstrumentID(resp.Argument.InstrumentID)
|
||||
pair, err := currency.NewPairFromString(resp.Argument.InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -809,13 +810,11 @@ func (ok *Okx) wsProcessOrderBooks(data []byte) error {
|
||||
response.Action != wsOrderbookSnapshot {
|
||||
return errors.New("invalid order book action")
|
||||
}
|
||||
var pair currency.Pair
|
||||
var assets []asset.Item
|
||||
assets, err = ok.GetAssetsFromInstrumentTypeOrID(response.Argument.InstrumentType, response.Argument.InstrumentID)
|
||||
assets, err := ok.GetAssetsFromInstrumentTypeOrID(response.Argument.InstrumentType, response.Argument.InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pair, err = ok.GetPairFromInstrumentID(response.Argument.InstrumentID)
|
||||
pair, err := currency.NewPairFromString(response.Argument.InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1062,8 +1061,7 @@ func (ok *Okx) wsProcessTrades(data []byte) error {
|
||||
}
|
||||
trades := make([]trade.Data, 0, len(response.Data)*len(assets))
|
||||
for i := range response.Data {
|
||||
var pair currency.Pair
|
||||
pair, err = ok.GetPairFromInstrumentID(response.Data[i].InstrumentID)
|
||||
pair, err := currency.NewPairFromString(response.Data[i].InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1086,7 +1084,6 @@ func (ok *Okx) wsProcessTrades(data []byte) error {
|
||||
// wsProcessOrders handles websocket order push data responses.
|
||||
func (ok *Okx) wsProcessOrders(respRaw []byte) error {
|
||||
var response WsOrderResponse
|
||||
var pair currency.Pair
|
||||
err := json.Unmarshal(respRaw, &response)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1109,7 +1106,7 @@ func (ok *Okx) wsProcessOrders(respRaw []byte) error {
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
pair, err = ok.GetPairFromInstrumentID(response.Data[x].InstrumentID)
|
||||
pair, err := currency.NewPairFromString(response.Data[x].InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1189,7 +1186,7 @@ func (ok *Okx) wsProcessCandles(respRaw []byte) error {
|
||||
if len(response.Data) == 0 {
|
||||
return errNoCandlestickDataFound
|
||||
}
|
||||
pair, err := ok.GetPairFromInstrumentID(response.Argument.InstrumentID)
|
||||
pair, err := currency.NewPairFromString(response.Argument.InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1260,8 +1257,7 @@ func (ok *Okx) wsProcessTickers(data []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var c currency.Pair
|
||||
c, err = ok.GetPairFromInstrumentID(response.Data[i].InstrumentID)
|
||||
c, err := currency.NewPairFromString(response.Data[i].InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -259,9 +259,13 @@ func (ok *Okx) FetchTradablePairs(ctx context.Context, a asset.Item) (currency.P
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pf, err := ok.CurrencyPairs.GetFormat(a, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pairs := make([]currency.Pair, len(insts))
|
||||
for x := range insts {
|
||||
pairs[x], err = currency.NewPairDelimiter(insts[x].InstrumentID, ok.CurrencyPairs.ConfigFormat.Delimiter)
|
||||
pairs[x], err = currency.NewPairDelimiter(insts[x].InstrumentID, pf.Delimiter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -378,7 +382,7 @@ func (ok *Okx) UpdateTickers(ctx context.Context, assetType asset.Item) error {
|
||||
}
|
||||
|
||||
for y := range ticks {
|
||||
pair, err := ok.GetPairFromInstrumentID(ticks[y].InstrumentID)
|
||||
pair, err := currency.NewPairFromString(ticks[y].InstrumentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1192,8 +1196,7 @@ allOrders:
|
||||
break allOrders
|
||||
}
|
||||
orderSide := orderList[i].Side
|
||||
var pair currency.Pair
|
||||
pair, err = ok.GetPairFromInstrumentID(orderList[i].InstrumentID)
|
||||
pair, err := currency.NewPairFromString(orderList[i].InstrumentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1286,8 +1289,7 @@ allOrders:
|
||||
// reached end of orders to crawl
|
||||
break allOrders
|
||||
}
|
||||
var pair currency.Pair
|
||||
pair, err = ok.GetPairFromInstrumentID(orderList[i].InstrumentID)
|
||||
pair, err := currency.NewPairFromString(orderList[i].InstrumentID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user