diff --git a/exchanges/binance/binance_live_test.go b/exchanges/binance/binance_live_test.go index 2ccf48c2..46bf3c1b 100644 --- a/exchanges/binance/binance_live_test.go +++ b/exchanges/binance/binance_live_test.go @@ -20,7 +20,7 @@ var mockTests = false func TestMain(m *testing.M) { b = new(Binance) - if err := testexch.TestInstance(b); err != nil { + if err := testexch.Setup(b); err != nil { log.Fatal(err) } diff --git a/exchanges/binance/binance_mock_test.go b/exchanges/binance/binance_mock_test.go index 85cb95b1..6d074e27 100644 --- a/exchanges/binance/binance_mock_test.go +++ b/exchanges/binance/binance_mock_test.go @@ -21,7 +21,7 @@ func TestMain(m *testing.M) { } b = new(Binance) - if err := testexch.TestInstance(b); err != nil { + if err := testexch.Setup(b); err != nil { log.Fatal(err) } diff --git a/exchanges/kraken/kraken_test.go b/exchanges/kraken/kraken_test.go index 7e024911..596f8900 100644 --- a/exchanges/kraken/kraken_test.go +++ b/exchanges/kraken/kraken_test.go @@ -47,7 +47,7 @@ const ( func TestMain(m *testing.M) { k = new(Kraken) - if err := testexch.TestInstance(k); err != nil { + if err := testexch.Setup(k); err != nil { log.Fatal(err) } if apiKey != "" && apiSecret != "" { diff --git a/exchanges/kucoin/kucoin_test.go b/exchanges/kucoin/kucoin_test.go index 4df68809..d43cb821 100644 --- a/exchanges/kucoin/kucoin_test.go +++ b/exchanges/kucoin/kucoin_test.go @@ -2736,8 +2736,7 @@ func TestGetOpenInterest(t *testing.T) { t.Parallel() nu := new(Kucoin) - require.NoError(t, testexch.TestInstance(nu), "TestInstance setup should not error") - + require.NoError(t, testexch.Setup(nu), "Test exchange Setup must not error") _, err := nu.GetOpenInterest(context.Background(), key.PairAsset{ Base: currency.ETH.Item, Quote: currency.USDT.Item, diff --git a/internal/testing/exchange/exchange.go b/internal/testing/exchange/exchange.go index 27db6e21..af44c859 100644 --- a/internal/testing/exchange/exchange.go +++ b/internal/testing/exchange/exchange.go @@ -7,6 +7,7 @@ import ( "log" "net/http" "net/http/httptest" + "path/filepath" "strings" "sync" "testing" @@ -19,12 +20,19 @@ import ( "github.com/thrasher-corp/gocryptotrader/exchanges/mock" "github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues" "github.com/thrasher-corp/gocryptotrader/exchanges/subscription" + testutils "github.com/thrasher-corp/gocryptotrader/internal/testing/utils" ) -// TestInstance takes an empty exchange instance and loads config for it from testdata/configtest and connects a NewTestWebsocket -func TestInstance(e exchange.IBotExchange) error { +// Setup takes an empty exchange instance and loads config for it from testdata/configtest and connects a NewTestWebsocket +func Setup(e exchange.IBotExchange) error { cfg := &config.Config{} - err := cfg.LoadConfig("../../testdata/configtest.json", true) + + root, err := testutils.RootPathFromCWD() + if err != nil { + return err + } + + err = cfg.LoadConfig(filepath.Join(root, "testdata", "configtest.json"), true) if err != nil { return fmt.Errorf("LoadConfig() error: %w", err) } @@ -92,7 +100,7 @@ func MockWsInstance[T any, PT interface { tb.Helper() e := PT(new(T)) - require.NoError(tb, TestInstance(e), "TestInstance setup should not error") + require.NoError(tb, Setup(e), "Test exchange Setup must not error") s := httptest.NewServer(h) diff --git a/internal/testing/exchange/exchange_test.go b/internal/testing/exchange/exchange_test.go new file mode 100644 index 00000000..d6796c9e --- /dev/null +++ b/internal/testing/exchange/exchange_test.go @@ -0,0 +1,35 @@ +package exchange + +import ( + "testing" + + "github.com/gorilla/websocket" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/thrasher-corp/gocryptotrader/config" + "github.com/thrasher-corp/gocryptotrader/exchanges/binance" + "github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues" +) + +// TestSetup exercises Setup +func TestSetup(t *testing.T) { + b := new(binance.Binance) + require.NoError(t, Setup(b), "Setup must not error") + assert.NotNil(t, b.Websocket, "Websocket should not be nil after Setup") + + e := new(sharedtestvalues.CustomEx) + assert.ErrorIs(t, Setup(e), config.ErrExchangeNotFound, "Setup should error correctly on a missing exchange") +} + +// TestMockHTTPInstance exercises MockHTTPInstance +func TestMockHTTPInstance(t *testing.T) { + b := new(binance.Binance) + require.NoError(t, Setup(b), "Test exchange Setup must not error") + require.NoError(t, MockHTTPInstance(b), "MockHTTPInstance must not error") +} + +// TestMockWsInstance exercises MockWsInstance +func TestMockWsInstance(t *testing.T) { + b := MockWsInstance[binance.Binance](t, CurryWsMockUpgrader(t, func(_ []byte, _ *websocket.Conn) error { return nil })) + require.NotNil(t, b, "MockWsInstance must not be nil") +} diff --git a/internal/testing/exchange/testdata/http.json b/internal/testing/exchange/testdata/http.json new file mode 100755 index 00000000..f1eae1f3 --- /dev/null +++ b/internal/testing/exchange/testdata/http.json @@ -0,0 +1,3 @@ +{ + "routes": null +} \ No newline at end of file diff --git a/internal/testing/utils/path.go b/internal/testing/utils/path.go new file mode 100644 index 00000000..52925fa6 --- /dev/null +++ b/internal/testing/utils/path.go @@ -0,0 +1,35 @@ +package path + +import ( + "errors" + "os" + "path/filepath" + "strings" +) + +// Exported public errors +var ( + ErrRootNotFound = errors.New("could not find root of gocryptotrader") +) + +// RootPathFromCWD returns the system path to GoCryptoTrader from the current working directory +// Expects to find LICENSE file +func RootPathFromCWD() (string, error) { + wd, err := os.Getwd() + if err != nil { + return "", err + } + return RootPath(wd) +} + +// RootPath returns the system path to GoCryptoTrader from a sub-directory path +func RootPath(p string) (string, error) { + parts := strings.Split(p, string(filepath.Separator)) + for i := len(parts); i > 0; i-- { + dir := strings.Join(parts[:i], string(filepath.Separator)) + if _, err := os.Stat(filepath.Join(dir, "LICENSE")); err == nil { + return dir, nil + } + } + return "", ErrRootNotFound +} diff --git a/internal/testing/utils/path_test.go b/internal/testing/utils/path_test.go new file mode 100644 index 00000000..623455f7 --- /dev/null +++ b/internal/testing/utils/path_test.go @@ -0,0 +1,38 @@ +package path + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// TestRootPathFromCWD exercises RootPathFromCWD and RootPath +func TestRootPathFromCWD(t *testing.T) { + r, err := RootPathFromCWD() + require.NoError(t, err) + _, err = os.Stat(filepath.Join(r, "LICENSE")) + require.NoError(t, err, "Must find a LICENSE file") + + // Ensure there are no other license files in sub-directories + err = filepath.WalkDir(r, func(p string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + // Skip the root of the project + w, _ := filepath.Split(p) + w = filepath.Clean(w) + if w == r { + return nil + } + if d.Type().IsRegular() && d.Name() == "LICENSE" { + return fmt.Errorf("found an unexpected LICENSE file in a sub-directory: %s", p) + } + return nil + }) + assert.NoError(t, err) +}