package gateio import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/thrasher-corp/gocryptotrader/currency" "github.com/thrasher-corp/gocryptotrader/exchanges/asset" "github.com/thrasher-corp/gocryptotrader/exchanges/kline" "github.com/thrasher-corp/gocryptotrader/exchanges/orderbook" "github.com/thrasher-corp/gocryptotrader/exchanges/subscription" testexch "github.com/thrasher-corp/gocryptotrader/internal/testing/exchange" ) func TestProcessOrderbookUpdate(t *testing.T) { t.Parallel() m := newWsOBUpdateManager(0) err := m.ProcessOrderbookUpdate(t.Context(), e, 1337, &orderbook.Update{}) assert.ErrorIs(t, err, currency.ErrCurrencyPairEmpty) pair := currency.NewPair(currency.BABY, currency.BABYDOGE) err = e.Websocket.Orderbook.LoadSnapshot(&orderbook.Book{ Exchange: e.Name, Pair: pair, Asset: asset.USDTMarginedFutures, Bids: []orderbook.Level{{Price: 1, Amount: 1}}, Asks: []orderbook.Level{{Price: 1, Amount: 1}}, LastUpdated: time.Now(), LastPushed: time.Now(), LastUpdateID: 1336, }) require.NoError(t, err) err = m.ProcessOrderbookUpdate(t.Context(), e, 1337, &orderbook.Update{ UpdateID: 1338, Pair: pair, Asset: asset.USDTMarginedFutures, AllowEmpty: true, UpdateTime: time.Now(), }) require.NoError(t, err) // Test orderbook snapshot is behind update err = m.ProcessOrderbookUpdate(t.Context(), e, 1340, &orderbook.Update{ UpdateID: 1341, Pair: pair, Asset: asset.USDTMarginedFutures, AllowEmpty: true, UpdateTime: time.Now(), }) require.NoError(t, err) cache := m.LoadCache(pair, asset.USDTMarginedFutures) cache.mtx.Lock() assert.Len(t, cache.updates, 1) assert.True(t, cache.updating) cache.mtx.Unlock() // Test orderbook snapshot is behind update err = m.ProcessOrderbookUpdate(t.Context(), e, 1342, &orderbook.Update{ UpdateID: 1343, Pair: pair, Asset: asset.USDTMarginedFutures, AllowEmpty: true, UpdateTime: time.Now(), }) require.NoError(t, err) cache.mtx.Lock() assert.Len(t, cache.updates, 2) assert.True(t, cache.updating) cache.mtx.Unlock() time.Sleep(time.Millisecond * 2) // Allow sync delay to pass cache.mtx.Lock() assert.Empty(t, cache.updates) assert.False(t, cache.updating) cache.mtx.Unlock() } func TestLoadCache(t *testing.T) { t.Parallel() m := newWsOBUpdateManager(0) pair := currency.NewPair(currency.BABY, currency.BABYDOGE) cache := m.LoadCache(pair, asset.USDTMarginedFutures) assert.NotNil(t, cache) assert.Len(t, m.lookup, 1) // Test cache is reused cache2 := m.LoadCache(pair, asset.USDTMarginedFutures) assert.Equal(t, cache, cache2) } func TestSyncOrderbook(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") require.NoError(t, e.UpdateTradablePairs(t.Context())) // Add dummy subscription so that it can be matched and a limit/level can be extracted for initial orderbook sync spot. err := e.Websocket.AddSubscriptions(nil, &subscription.Subscription{Channel: subscription.OrderbookChannel, Interval: kline.HundredMilliseconds}) require.NoError(t, err) m := newWsOBUpdateManager(defaultWSSnapshotSyncDelay) for _, a := range []asset.Item{asset.Spot, asset.USDTMarginedFutures} { pair := currency.NewPair(currency.ETH, currency.USDT) err := e.CurrencyPairs.EnablePair(a, pair) require.NoError(t, err) cache := m.LoadCache(pair, a) cache.updates = []pendingUpdate{{update: &orderbook.Update{Pair: pair, Asset: a}}} cache.updating = true err = cache.SyncOrderbook(t.Context(), e, pair, a) require.NoError(t, err) require.False(t, cache.updating) require.Empty(t, cache.updates) expectedLimit := 20 if a == asset.Spot { expectedLimit = 100 } b, err := e.Websocket.Orderbook.GetOrderbook(pair, a) require.NoError(t, err) require.Len(t, b.Bids, expectedLimit) require.Len(t, b.Asks, expectedLimit) } } func TestApplyPendingUpdates(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") require.NoError(t, e.UpdateTradablePairs(t.Context())) m := newWsOBUpdateManager(defaultWSSnapshotSyncDelay) pair := currency.NewPair(currency.LTC, currency.USDT) err := e.Websocket.Orderbook.LoadSnapshot(&orderbook.Book{ Exchange: e.Name, Pair: pair, Asset: asset.USDTMarginedFutures, Bids: []orderbook.Level{{Price: 1, Amount: 1}}, Asks: []orderbook.Level{{Price: 1, Amount: 1}}, LastUpdated: time.Now(), LastPushed: time.Now(), LastUpdateID: 1335, }) require.NoError(t, err) cache := m.LoadCache(pair, asset.USDTMarginedFutures) update := &orderbook.Update{ UpdateID: 1339, Pair: pair, Asset: asset.USDTMarginedFutures, AllowEmpty: true, UpdateTime: time.Now(), } cache.updates = []pendingUpdate{{update: update, firstUpdateID: 1337}} err = cache.applyPendingUpdates(e, asset.USDTMarginedFutures) require.ErrorIs(t, err, errOrderbookSnapshotOutdated) cache.updates[0].firstUpdateID = 1336 err = cache.applyPendingUpdates(e, asset.USDTMarginedFutures) require.NoError(t, err) } func TestApplyOrderbookUpdate(t *testing.T) { t.Parallel() e := new(Exchange) require.NoError(t, testexch.Setup(e), "Setup must not error") require.NoError(t, e.UpdateTradablePairs(t.Context())) pair := currency.NewBTCUSDT() update := &orderbook.Update{ Pair: pair, Asset: asset.USDTMarginedFutures, AllowEmpty: true, UpdateTime: time.Now(), } err := applyOrderbookUpdate(e, update) require.ErrorIs(t, err, orderbook.ErrDepthNotFound) update.Asset = asset.Spot err = applyOrderbookUpdate(e, update) require.ErrorIs(t, err, orderbook.ErrDepthNotFound) update.Pair = currency.NewPair(currency.BABY, currency.BABYDOGE) err = applyOrderbookUpdate(e, update) require.NoError(t, err) }