mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
* Websocket: Use ErrSubscribedAlready instead of errChannelAlreadySubscribed * Subscriptions: Replace Pair with Pairs Given that some subscriptions have multiple pairs, support that as the standard. * Docs: Update subscriptions in add new exch * RPC: Update Subscription Pairs * Linter: Disable testifylint.Len We deliberately use Equal over Len to avoid spamming the contents of large Slices * Websocket: Add suffix to state consts * Binance: Subscription Pairs support * Bitfinex: Subscription Pairs support * Bithumb: Subscription Pairs support * Bitmex: Subscription Pairs support * Bitstamp: Subscription Pairs support * BTCMarkets: Subscription Pairs support * BTSE: Subscription Pairs support * Coinbase: Subscription Pairs support * Coinut: Subscription Pairs support * GateIO: Subscription Pairs support * Gemini: Subscription Pairs support and improvement * Hitbtc: Subscription Pairs support * Huboi: Subscription Pairs support * Kucoin: Subscription Pairs support * Okcoin: Subscription Pairs support * Poloniex: Subscription Pairs support * Kraken: Add subscription Pairs support Note: This is a naieve implementation because we want to rebase the kraken websocket rewrite on top of this * Bybit: Subscription Pairs support * Okx: Subscription Pairs support * Bitmex: Subsription configuration * Fixes unauthenticated websocket left as CanUseAuth * Fixes auth subs happening privately * CoinbasePro: Subscription Configuration * Consolidate ProductIDs when all subscriptions are for the same list * Websocket: Log actual sent message when Verbose * Subscriptions: Improve clarity of which key is which in Match * Subscriptions: Lint fix for HugeParam * Subscriptions: Add AddPairs and move keys from test * Subscriptions: Simplify subscription keys and add key types * Subscriptions: Add List.GroupPairs Rename sub.AddPairs * Subscription: Fix ExactKey not matching 0 pairs * Subscriptions: Remove unused IdentityKey and HasPairKey * Subscriptions: Fix GetKey test * Subscriptions: Test coverage improvements * Websocket: Change State on Add/Remove * Subscriptions: Improve error context * Subscriptions: Fix Enable: false subs not ignored * Bitfinex: Fix WsAuth test failing on DataHandler DataHandler is eaten by dataMonitor now, so we need to use ToRoutine * Deribit: Subscription Pairs support * Websocket: Accept nil lists for checkSubscriptions If the user passes in a nil (implicitly empty) list, we would not panic. Therefore the burden of correctness about that data lies with them. The list of subscriptions is empty, and that's okay, and possibly convenient * Websocket: Add context to NilPointer errors * Subscriptions: Add context to nil errors * Exchange: Fix error expectations in UnsubToWSChans
188 lines
6.0 KiB
Go
188 lines
6.0 KiB
Go
package sharedtestvalues
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"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/stream"
|
|
)
|
|
|
|
// This package is only to be referenced in test files
|
|
const (
|
|
// WebsocketResponseDefaultTimeout used in websocket testing
|
|
// Defines wait time for receiving websocket response before cancelling
|
|
WebsocketResponseDefaultTimeout = 3 * time.Second
|
|
// WebsocketResponseExtendedTimeout used in websocket testing
|
|
// Defines wait time for receiving websocket response before cancelling
|
|
WebsocketResponseExtendedTimeout = 15 * time.Second
|
|
// WebsocketChannelOverrideCapacity used in websocket testing
|
|
// Defines channel capacity as defaults size can block tests
|
|
WebsocketChannelOverrideCapacity = 500
|
|
|
|
MockTesting = "Mock testing framework in use for %s exchange on REST endpoints only"
|
|
LiveTesting = "Mock testing bypassed; live testing of REST endpoints in use for %s exchange"
|
|
|
|
warningSkip = "Skipping test"
|
|
warningKeys = "API test keys have not been set"
|
|
warningManipulateOrders = "variable `canManipulateRealOrders` is false"
|
|
warningHowTo = "these values can be set at the top of the test file."
|
|
)
|
|
|
|
// GetWebsocketInterfaceChannelOverride returns a new interface based channel
|
|
// with the capacity set to WebsocketChannelOverrideCapacity
|
|
func GetWebsocketInterfaceChannelOverride() chan interface{} {
|
|
return make(chan interface{}, WebsocketChannelOverrideCapacity)
|
|
}
|
|
|
|
// GetWebsocketStructChannelOverride returns a new struct based channel
|
|
// with the capacity set to WebsocketChannelOverrideCapacity
|
|
func GetWebsocketStructChannelOverride() chan struct{} {
|
|
return make(chan struct{}, WebsocketChannelOverrideCapacity)
|
|
}
|
|
|
|
// NewTestWebsocket returns a test websocket object
|
|
func NewTestWebsocket() *stream.Websocket {
|
|
w := stream.NewWebsocket()
|
|
w.DataHandler = make(chan interface{}, WebsocketChannelOverrideCapacity)
|
|
w.ToRoutine = make(chan interface{}, 1000)
|
|
return w
|
|
}
|
|
|
|
// SkipTestIfCredentialsUnset is a test helper function checking if the
|
|
// authenticated function can perform the required test.
|
|
func SkipTestIfCredentialsUnset(t *testing.T, exch exchange.IBotExchange, canManipulateOrders ...bool) {
|
|
t.Helper()
|
|
|
|
if len(canManipulateOrders) > 1 {
|
|
t.Fatal("more than one canManipulateOrders boolean value has been supplied, please remove")
|
|
}
|
|
|
|
areTestAPICredentialsSet := AreAPICredentialsSet(exch)
|
|
supportsManipulatingOrders := len(canManipulateOrders) > 0
|
|
allowedToManipulateOrders := supportsManipulatingOrders && canManipulateOrders[0]
|
|
|
|
if (areTestAPICredentialsSet && !supportsManipulatingOrders) ||
|
|
(areTestAPICredentialsSet && allowedToManipulateOrders) {
|
|
return
|
|
}
|
|
|
|
message := []string{warningSkip}
|
|
if !areTestAPICredentialsSet {
|
|
message = append(message, warningKeys)
|
|
}
|
|
|
|
if supportsManipulatingOrders && !allowedToManipulateOrders {
|
|
message = append(message, warningManipulateOrders)
|
|
}
|
|
message = append(message, warningHowTo)
|
|
t.Skip(strings.Join(message, ", "))
|
|
}
|
|
|
|
// SkipTestIfCannotManipulateOrders will only skip if the credentials are set
|
|
// correctly and can manipulate orders is set to false. It will continue normal
|
|
// operations if credentials are not set, giving better code coverage.
|
|
func SkipTestIfCannotManipulateOrders(t *testing.T, exch exchange.IBotExchange, canManipulateOrders bool) {
|
|
t.Helper()
|
|
|
|
if !AreAPICredentialsSet(exch) || canManipulateOrders {
|
|
return
|
|
}
|
|
|
|
t.Skip(warningSkip + ", " + warningManipulateOrders)
|
|
}
|
|
|
|
// AreAPICredentialsSet returns if the API credentials are set.
|
|
func AreAPICredentialsSet(exch exchange.IBotExchange) bool {
|
|
return exch.VerifyAPICredentials(exch.GetDefaultCredentials()) == nil
|
|
}
|
|
|
|
// EmptyStringPotentialPattern is a regular expression pattern for a potential
|
|
// empty string into float64
|
|
var EmptyStringPotentialPattern = `.*float64.*json:"[^"]*,string".*`
|
|
|
|
// ForceFileStandard will check all files in the current directory for a regular
|
|
// expression pattern. If the pattern is found the test will fail.
|
|
func ForceFileStandard(t *testing.T, pattern string) error {
|
|
t.Helper()
|
|
|
|
r := regexp.MustCompile(pattern)
|
|
|
|
root := "." // Specify the root directory to start walking from
|
|
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !info.IsDir() && strings.HasSuffix(path, ".go") {
|
|
fileContents, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatalf("Failed to read file: %v", err)
|
|
}
|
|
|
|
lines := bytes.Split(fileContents, []byte("\n"))
|
|
for x, line := range lines {
|
|
if r.Match(line) {
|
|
t.Errorf("File: %s line contains pattern [%s] match with [%s] at line %d", path, pattern, string(line), x+1)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to walk directory: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// SetupCurrencyPairsForExchangeAsset enables an asset for an exchange
|
|
// and adds the currency pair(s) to the available and enabled list of existing pairs
|
|
// if it is already enabled or part of the pairs, no error is raised
|
|
func SetupCurrencyPairsForExchangeAsset(t *testing.T, exch exchange.IBotExchange, a asset.Item, cp ...currency.Pair) {
|
|
t.Helper()
|
|
if len(cp) == 0 {
|
|
return
|
|
}
|
|
b := exch.GetBase()
|
|
err := b.CurrencyPairs.SetAssetEnabled(a, true)
|
|
if err != nil && !errors.Is(err, currency.ErrAssetAlreadyEnabled) {
|
|
t.Fatal(err)
|
|
}
|
|
availPairs, err := b.CurrencyPairs.GetPairs(a, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
apLen := len(availPairs)
|
|
enabledPairs, err := b.CurrencyPairs.GetPairs(a, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
epLen := len(enabledPairs)
|
|
for i := range cp {
|
|
availPairs = availPairs.Add(cp[i])
|
|
enabledPairs = enabledPairs.Add(cp[i])
|
|
}
|
|
if len(availPairs) != apLen {
|
|
err = b.CurrencyPairs.StorePairs(a, availPairs, false)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if len(enabledPairs) != epLen {
|
|
err = b.CurrencyPairs.StorePairs(a, enabledPairs, true)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
}
|