mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
If one asset is enabled but has no enabled pairs, we should ignore that asset, even for non-pair related subscriptions. That matches the existing code, but wasn't happening in the context of asset.All subscriptions with just one asset in this state. If a user wanted to have non-pair subscriptions, they should use asset.Empty. Would expect other breakages with no pairs enabled, too. Note: No enabled pairs for an enabled asset is a transient issue which can occur due to enableOnePair racing against no available pairs. The second run, available pairs would be populated and enableOnePair would work. This situation could persist due to running with --dry or containerised, though. Fixes: ` Okx websocket: subscription failure, myOrders all : subscription template did not generate the expected number of pair records for spread: Got 1; Expected 0 ` Relates to #1420
152 lines
7.0 KiB
Go
152 lines
7.0 KiB
Go
package subscription
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/thrasher-corp/gocryptotrader/common"
|
|
"github.com/thrasher-corp/gocryptotrader/currency"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
|
"github.com/thrasher-corp/gocryptotrader/exchanges/kline"
|
|
)
|
|
|
|
// TestExpandTemplates exercises ExpandTemplates
|
|
func TestExpandTemplates(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
e := newMockEx()
|
|
e.tpl = "subscriptions.tmpl"
|
|
|
|
// Functionality tests
|
|
l := List{
|
|
{Channel: "single-channel"},
|
|
{Channel: "expand-assets", Asset: asset.All, Interval: kline.FifteenMin},
|
|
{Channel: "expand-pairs", Asset: asset.All, Levels: 1},
|
|
{Channel: "expand-pairs", Asset: asset.Spot, Levels: 2},
|
|
{Channel: "single-channel", QualifiedChannel: "just one sub already processed"},
|
|
{Channel: "update-asset-pairs", Asset: asset.All},
|
|
{Channel: "expand-pairs", Asset: asset.Spot, Pairs: e.pairs[asset.Spot][0:2], Levels: 3},
|
|
{Channel: "batching", Asset: asset.Spot},
|
|
{Channel: "single-channel", Authenticated: true},
|
|
}
|
|
got, err := l.ExpandTemplates(e)
|
|
require.NoError(t, err, "ExpandTemplates must not error")
|
|
exp := List{
|
|
{Channel: "single-channel", QualifiedChannel: "single-channel"},
|
|
{Channel: "expand-assets", QualifiedChannel: "spot-expand-assets@15m", Asset: asset.Spot, Pairs: e.pairs[asset.Spot], Interval: kline.FifteenMin},
|
|
{Channel: "expand-assets", QualifiedChannel: "future-expand-assets@15m", Asset: asset.Futures, Pairs: e.pairs[asset.Futures], Interval: kline.FifteenMin},
|
|
{Channel: "single-channel", QualifiedChannel: "just one sub already processed"},
|
|
{Channel: "update-asset-pairs", QualifiedChannel: "spot-btcusdt-update-asset-pairs", Asset: asset.Spot, Pairs: currency.Pairs{btcusdtPair}},
|
|
{Channel: "expand-pairs", QualifiedChannel: "spot-USDTBTC-expand-pairs@3", Asset: asset.Spot, Pairs: e.pairs[asset.Spot][1:2], Levels: 3},
|
|
{Channel: "expand-pairs", QualifiedChannel: "spot-USDCETH-expand-pairs@3", Asset: asset.Spot, Pairs: e.pairs[asset.Spot][:1], Levels: 3},
|
|
}
|
|
for a, pairs := range e.pairs {
|
|
if a == asset.Index { // Not IsAssetWebsocketEnabled
|
|
continue
|
|
}
|
|
for _, p := range common.SortStrings(pairs) {
|
|
pStr := p.Swap().String()
|
|
if a == asset.Spot {
|
|
exp = append(exp, List{
|
|
{Channel: "expand-pairs", QualifiedChannel: "spot-" + pStr + "-expand-pairs@1", Asset: a, Pairs: currency.Pairs{p}, Levels: 1},
|
|
&Subscription{Channel: "expand-pairs", QualifiedChannel: "spot-" + pStr + "-expand-pairs@2", Asset: a, Pairs: currency.Pairs{p}, Levels: 2},
|
|
}...)
|
|
} else {
|
|
exp = append(exp,
|
|
&Subscription{Channel: "expand-pairs", QualifiedChannel: "future-" + pStr + "-expand-pairs@1", Asset: a, Pairs: currency.Pairs{p}, Levels: 1},
|
|
)
|
|
}
|
|
}
|
|
}
|
|
for _, b := range common.Batch(common.SortStrings(e.pairs[asset.Spot]), 3) {
|
|
exp = append(exp, &Subscription{Channel: "batching", QualifiedChannel: "spot-" + b.Join() + "-batching", Asset: asset.Spot, Pairs: b})
|
|
}
|
|
|
|
if !equalLists(t, exp, got) {
|
|
t.FailNow() // If the first list isn't equal testing it again will duplicate test failures
|
|
}
|
|
|
|
e.auth = true
|
|
got, err = l.ExpandTemplates(e)
|
|
require.NoError(t, err, "ExpandTemplates must not error")
|
|
exp = append(exp, &Subscription{Channel: "single-channel", QualifiedChannel: "single-channel-authed"})
|
|
equalLists(t, exp, got)
|
|
|
|
// Test with just one asset to ensure asset.All works, and disabled assets don't error
|
|
e.assets = e.assets[:1]
|
|
l = List{
|
|
{Channel: "expand-assets", Asset: asset.All, Interval: kline.OneHour},
|
|
{Channel: "expand-pairs", Asset: asset.All, Levels: 4},
|
|
{Channel: "single-channel", Asset: asset.Futures},
|
|
}
|
|
got, err = l.ExpandTemplates(e)
|
|
require.NoError(t, err, "ExpandTemplates must not error")
|
|
exp = List{
|
|
{Channel: "expand-assets", QualifiedChannel: "spot-expand-assets@1h", Asset: asset.Spot, Pairs: e.pairs[asset.Spot], Interval: kline.OneHour},
|
|
}
|
|
for _, p := range e.pairs[asset.Spot] {
|
|
exp = append(exp, List{
|
|
{Channel: "expand-pairs", QualifiedChannel: "spot-" + p.Swap().String() + "-expand-pairs@4", Asset: asset.Spot, Pairs: currency.Pairs{p}, Levels: 4},
|
|
}...)
|
|
}
|
|
equalLists(t, exp, got)
|
|
|
|
// Users can specify pairs which aren't available, even across diverse assets
|
|
// Use-case: Coinbasepro user sub for futures BTC-USD would return all BTC pairs and all USD pairs, even though BTC-USD might not be enabled or available
|
|
p := currency.Pairs{currency.NewPairWithDelimiter("BEAR", "PEAR", "🐻")}
|
|
got, err = List{{Channel: "expand-pairs", Asset: asset.All, Pairs: p}}.ExpandTemplates(e)
|
|
require.NoError(t, err, "Must not error with fictional pairs")
|
|
exp = List{{Channel: "expand-pairs", QualifiedChannel: "spot-PEARBEAR-expand-pairs@0", Asset: asset.Spot, Pairs: p}}
|
|
equalLists(t, exp, got)
|
|
|
|
// Error cases
|
|
_, err = List{{Channel: "nil"}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, errInvalidTemplate, "Should get correct error on nil template")
|
|
|
|
e.tpl = "errors.tmpl"
|
|
|
|
_, err = List{{Channel: "error1"}}.ExpandTemplates(e)
|
|
assert.ErrorContains(t, err, "wrong number of args for String", "Should error correctly with execution error")
|
|
|
|
_, err = List{{Channel: "empty-content", Asset: asset.Spot}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, errNoTemplateContent, "Should error correctly when no content generated")
|
|
assert.ErrorContains(t, err, "empty-content", "Should error correctly when no content generated")
|
|
|
|
_, err = List{{Channel: "error2", Asset: asset.All}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, errAssetRecords, "Should error correctly when invalid number of asset entries")
|
|
|
|
_, err = List{{Channel: "error3", Asset: asset.Spot}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, errPairRecords, "Should error correctly when invalid number of pair entries")
|
|
|
|
_, err = List{{Channel: "error4", Asset: asset.Spot}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, errTooManyBatchSizePerAsset, "Should error correctly when too many BatchSize directives")
|
|
|
|
_, err = List{{Channel: "error5", Asset: asset.Spot}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, common.ErrTypeAssertFailure, "Should error correctly when batch size isn't an int")
|
|
|
|
e.tpl = "parse-error.tmpl"
|
|
e.tpl = "parse-error.tmpl"
|
|
_, err = l.ExpandTemplates(e)
|
|
assert.ErrorContains(t, err, "function \"explode\" not defined", "Should error correctly on unparsable template")
|
|
|
|
e.errFormat = errors.New("the planet Krypton is gone")
|
|
_, err = l.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, e.errFormat, "Should error correctly on GetPairFormat")
|
|
|
|
e.errPairs = errors.New("bad parenting from Jor-El")
|
|
_, err = l.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, e.errPairs, "Should error correctly on GetEnabledPairs")
|
|
|
|
l = List{{Channel: "single-channel", QualifiedChannel: "already happy"}}
|
|
got, err = l.ExpandTemplates(e)
|
|
require.NoError(t, err)
|
|
require.Len(t, got, 1, "Must get back the one sub")
|
|
assert.Equal(t, "already happy", l[0].QualifiedChannel, "Should get back the one sub")
|
|
assert.NotSame(t, &got, &l, "Should get back a different actual list")
|
|
|
|
_, err = List{{Channel: "nil"}}.ExpandTemplates(e)
|
|
assert.ErrorIs(t, err, errInvalidTemplate, "Should get correct error on nil template")
|
|
}
|