mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-22 23:16:48 +00:00
Config: Refactor version packages (#1887)
* Config: Move config versions to separate pacakges * Config: Move version tests to blackbox texts * Config: Protect registerVersion from overflow * Config: Protect against version already registered
This commit is contained in:
76
config/versions/v4/v4.go
Normal file
76
config/versions/v4/v4.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package v4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
)
|
||||
|
||||
// Version is an Exchange upgrade to move currencyPairs.assetTypes to currencyPairs.pairs.*.assetEnabled
|
||||
type Version struct{}
|
||||
|
||||
// Exchanges returns all exchanges: "*"
|
||||
func (*Version) Exchanges() []string { return []string{"*"} }
|
||||
|
||||
// UpgradeExchange sets AssetEnabled: true for all assets listed in assetTypes, and false for any with no field
|
||||
func (*Version) UpgradeExchange(_ context.Context, e []byte) ([]byte, error) {
|
||||
toEnable := map[string]bool{}
|
||||
|
||||
assetTypesFn := func(asset []byte, valueType jsonparser.ValueType, _ int, _ error) {
|
||||
if valueType == jsonparser.String {
|
||||
toEnable[string(asset)] = true
|
||||
}
|
||||
}
|
||||
_, err := jsonparser.ArrayEach(e, assetTypesFn, "currencyPairs", "assetTypes")
|
||||
if err != nil && !errors.Is(err, jsonparser.KeyPathNotFoundError) {
|
||||
return e, fmt.Errorf("error upgrading assetTypes: %w", err)
|
||||
}
|
||||
|
||||
assetEnabledFn := func(assetBytes, v []byte, _ jsonparser.ValueType, _ int) (err error) {
|
||||
asset := string(assetBytes)
|
||||
if toEnable[asset] {
|
||||
e, err = jsonparser.Set(e, []byte(`true`), "currencyPairs", "pairs", asset, "assetEnabled")
|
||||
} else {
|
||||
var vT jsonparser.ValueType
|
||||
_, vT, _, err = jsonparser.Get(v, "assetEnabled")
|
||||
switch {
|
||||
case vT == jsonparser.Null, errors.Is(err, jsonparser.KeyPathNotFoundError):
|
||||
e, err = jsonparser.Set(e, []byte(`false`), "currencyPairs", "pairs", asset, "assetEnabled")
|
||||
case err == nil && vT != jsonparser.Boolean:
|
||||
err = fmt.Errorf("assetEnabled: %w (`%s`)", jsonparser.UnknownValueTypeError, vT)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%w for asset `%s`", err, asset)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if err = jsonparser.ObjectEach(bytes.Clone(e), assetEnabledFn, "currencyPairs", "pairs"); err != nil {
|
||||
return e, fmt.Errorf("error upgrading currencyPairs.pairs: %w", err)
|
||||
}
|
||||
e = jsonparser.Delete(e, "currencyPairs", "assetTypes")
|
||||
return e, err
|
||||
}
|
||||
|
||||
// DowngradeExchange moves AssetEnabled assets into AssetType field
|
||||
func (*Version) DowngradeExchange(_ context.Context, e []byte) ([]byte, error) {
|
||||
assetTypes := []string{}
|
||||
|
||||
assetEnabledFn := func(asset, v []byte, _ jsonparser.ValueType, _ int) error {
|
||||
if b, err := jsonparser.GetBoolean(v, "assetEnabled"); err == nil {
|
||||
if b {
|
||||
assetTypes = append(assetTypes, fmt.Sprintf("%q", asset))
|
||||
}
|
||||
e = jsonparser.Delete(e, "currencyPairs", "pairs", string(asset), "assetEnabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := jsonparser.ObjectEach(bytes.Clone(e), assetEnabledFn, "currencyPairs", "pairs"); err != nil {
|
||||
return e, err
|
||||
}
|
||||
return jsonparser.Set(e, []byte(`[`+strings.Join(assetTypes, ",")+`]`), "currencyPairs", "assetTypes")
|
||||
}
|
||||
87
config/versions/v4/v4_test.go
Normal file
87
config/versions/v4/v4_test.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package v4_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/buger/jsonparser"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
v4 "github.com/thrasher-corp/gocryptotrader/config/versions/v4"
|
||||
)
|
||||
|
||||
func TestExchanges(t *testing.T) {
|
||||
t.Parallel()
|
||||
assert.Equal(t, []string{"*"}, new(v4.Version).Exchanges())
|
||||
}
|
||||
|
||||
func TestUpgradeExchange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
_, err := new(v4.Version).UpgradeExchange(context.Background(), []byte{})
|
||||
require.ErrorContains(t, err, `error upgrading assetTypes`)
|
||||
|
||||
_, err = new(v4.Version).UpgradeExchange(context.Background(), []byte(`{}`))
|
||||
require.ErrorContains(t, err, `error upgrading currencyPairs.pairs`)
|
||||
|
||||
in := []byte(`{"name":"Cracken","currencyPairs":{"assetTypes":["spot"],"pairs":{"spot":{"enabled":"BTC-AUD","available":"BTC-AUD"},"futures":{"assetEnabled":true},"options":{},"margin":{"assetEnabled":null}}}}`)
|
||||
out, err := new(v4.Version).UpgradeExchange(context.Background(), in)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, out)
|
||||
|
||||
_, _, _, err = jsonparser.Get(out, "currencyPairs", "assetTypes") //nolint:dogsled // Ignored return values really not needed
|
||||
assert.ErrorIs(t, err, jsonparser.KeyPathNotFoundError, "assetTypes should be removed")
|
||||
|
||||
e, err := jsonparser.GetBoolean(out, "currencyPairs", "pairs", "spot", "assetEnabled")
|
||||
require.NoError(t, err, "Must find assetEnabled for spot")
|
||||
assert.True(t, e, "assetEnabled should be set to true")
|
||||
|
||||
e, err = jsonparser.GetBoolean(out, "currencyPairs", "pairs", "futures", "assetEnabled")
|
||||
require.NoError(t, err, "Must find assetEnabled for futures")
|
||||
assert.True(t, e, "assetEnabled should be set to true")
|
||||
|
||||
e, err = jsonparser.GetBoolean(out, "currencyPairs", "pairs", "options", "assetEnabled")
|
||||
require.NoError(t, err, "Must find assetEnabled for options")
|
||||
assert.False(t, e, "assetEnabled should be set to false")
|
||||
|
||||
e, err = jsonparser.GetBoolean(out, "currencyPairs", "pairs", "margin", "assetEnabled")
|
||||
require.NoError(t, err, "Must find assetEnabled for margin")
|
||||
assert.False(t, e, "assetEnabled should be set to false")
|
||||
|
||||
out2, err := new(v4.Version).UpgradeExchange(context.Background(), out)
|
||||
require.NoError(t, err, "Must not error on re-upgrading")
|
||||
assert.Equal(t, out, out2, "Should not affect an already upgraded config")
|
||||
|
||||
in = []byte(`{"name":"Cracken","currencyPairs":{"assetTypes":["spot"],"pairs":{"spot":{"assetEnabled":{}}}}}`)
|
||||
_, err = new(v4.Version).UpgradeExchange(context.Background(), in)
|
||||
require.NoError(t, err)
|
||||
|
||||
in = []byte(`{"name":"Cracken","currencyPairs":{"assetTypes":["spot"],"pairs":{"margin":{"assetEnabled":{}}}}}`)
|
||||
_, err = new(v4.Version).UpgradeExchange(context.Background(), in)
|
||||
require.ErrorIs(t, err, jsonparser.UnknownValueTypeError)
|
||||
require.ErrorContains(t, err, "`margin`")
|
||||
require.ErrorContains(t, err, "`object`")
|
||||
}
|
||||
|
||||
func TestDowngradeExchange(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
in := []byte(`{"name":"Cracken","currencyPairs":{"pairs":{"spot":{"enabled":"BTC-AUD","available":"BTC-AUD","assetEnabled":true},"futures":{"assetEnabled":false},"options":{},"options_combo":{"assetEnabled":true}}}}`)
|
||||
out, err := new(v4.Version).DowngradeExchange(context.Background(), in)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, out)
|
||||
|
||||
v, vT, _, err := jsonparser.Get(out, "currencyPairs", "assetTypes")
|
||||
require.NoError(t, err, "assetTypes must be found")
|
||||
require.Equal(t, jsonparser.Array, vT, "assetTypes must be an array")
|
||||
require.Equal(t, `["spot","options_combo"]`, string(v), "assetTypes must be correct")
|
||||
|
||||
assetEnabledFn := func(k, v []byte, _ jsonparser.ValueType, _ int) error {
|
||||
_, err = jsonparser.GetBoolean(v, "assetEnabled")
|
||||
require.ErrorIsf(t, err, jsonparser.KeyPathNotFoundError, "assetEnabled must be removed from %s", k)
|
||||
return nil
|
||||
}
|
||||
err = jsonparser.ObjectEach(bytes.Clone(out), assetEnabledFn, "currencyPairs", "pairs")
|
||||
require.NoError(t, err, "Must not error visiting currencyPairs")
|
||||
}
|
||||
Reference in New Issue
Block a user