mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 15:09:51 +00:00
* Okx: Fix WS order fields * Fixes float64 with string annotation erroring on empty strings: Okx Order Push Data error json: invalid use of ,string struct tag, trying to unmarshal "" into float64 Specifically this came from px field from a market order * Switch to convert.StringToFloat64 instead of okxNumericalValue * Fix typo in Notional* field names; Ironically prevented them from erroring * Okx: Add tests for first order fields * Okx: CID and maybe set WS order Filled time * Tests: Set TestFixtureToDataHandler to t.Helper * Orders: Add UnmarshalJSON to order.Side * Okx: Fix FillTime not parsed for PendingOrder * Okx: Switch to order.Side Unmarshal throughout * Okx: Add Fee and FeeAsset to order processing * Okx: Fix WS order.Detail amounts and Test This fixes Amount vs QuoteAmount for market sells where tgtCcy is quote_ccy * Add comment to order.Side.UnmarshalJSON * Okx: Replace PendingOrderItem Unmarshal with local types * Okx: string type for WS order reduceOnly Note: Not yet in unit tests, since it's not part of the spot tests I was originally fixing. I'll circle back to adding full test support for Reduce only and deleveraging positions. * Okx: Fix TestOrderPushData Amount We were expecting 0 when we're given a quoteAmount In reality, we'll calculate the size from the price * Okx: Fix order and remAmount in wsOrders Improved handling for Float64 issues and boundaries when the order is fully executed but not yet marked as Filled * Fix ErrSideIsInvalid in tests
186 lines
6.3 KiB
Go
186 lines
6.3 KiB
Go
package sharedtestvalues
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
|
"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 {
|
|
return &stream.Websocket{
|
|
Init: true,
|
|
DataHandler: make(chan interface{}, WebsocketChannelOverrideCapacity),
|
|
ToRoutine: make(chan interface{}, 1000),
|
|
TrafficAlert: make(chan struct{}),
|
|
ReadMessageErrors: make(chan error),
|
|
Subscribe: make(chan []stream.ChannelSubscription, 10),
|
|
Unsubscribe: make(chan []stream.ChannelSubscription, 10),
|
|
Match: stream.NewMatch(),
|
|
}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// TestFixtureToDataHandler takes a new empty exchange and configures a new websocket handler for it, and squirts the json path contents to it
|
|
// It accepts a reader function, which is probably e.wsHandleData but could be anything
|
|
func TestFixtureToDataHandler(t *testing.T, seed, e exchange.IBotExchange, fixturePath string, reader func([]byte) error) {
|
|
t.Helper()
|
|
b := e.GetBase()
|
|
seedBase := seed.GetBase()
|
|
|
|
err := b.CurrencyPairs.Load(&seedBase.CurrencyPairs)
|
|
assert.NoError(t, err, "Loading currency pairs should not error")
|
|
|
|
b.Name = "fixture"
|
|
b.Websocket = &stream.Websocket{
|
|
Wg: new(sync.WaitGroup),
|
|
DataHandler: make(chan interface{}, 128),
|
|
}
|
|
b.API.Endpoints = b.NewEndpoints()
|
|
|
|
fixture, err := os.Open(fixturePath)
|
|
assert.NoError(t, err, "Opening fixture '%s' should not error", fixturePath)
|
|
defer func() {
|
|
assert.NoError(t, fixture.Close(), "Closing the fixture file should not error")
|
|
}()
|
|
|
|
s := bufio.NewScanner(fixture)
|
|
for s.Scan() {
|
|
msg := s.Bytes()
|
|
if err := reader(msg); err != nil {
|
|
t.Errorf("%v from message: %s", err, msg)
|
|
}
|
|
}
|
|
assert.NoError(t, s.Err(), "Fixture Scanner should not error")
|
|
}
|