mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-08 07:26:48 +00:00
accounts: Move to instance methods, fix races and isolate tests (#1923)
* Bybit: Fix race in TestUpdateAccountInfo and TestWSHandleData * DriveBy rename TestWSHandleData * This doesn't address running with -race=2+ due to the singleton * Accounts: Add account.GetService() * exchange: Assertify TestSetupDefaults * Exchanges: Add account.Service override for testing * Exchanges: Remove duplicate IsWebsocketEnabled test from TestSetupDefaults * Dispatch: Replace nil checks with NilGuard * Engine: Remove deprecated printAccountHoldingsChangeSummary * Dispatcher: Add EnsureRunning method * Accounts: Move singleton accounts service to exchange Accounts * Move singleton accounts service to exchange Accounts This maintains the concept of a global store, whilst allowing exchanges to override it when needed, particularly for testing. APIServer: * Remove getAllActiveAccounts from apiserver Deprecated apiserver only thing using this, so remove it instead of updating it * Update comment for UpdateAccountBalances everywhere * Docs: Add punctuation to function comments * Bybit: Coverage for wsProcessWalletPushData Save
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/thrasher-corp/gocryptotrader/currency"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchange/accounts"
|
||||
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
|
||||
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
|
||||
"github.com/thrasher-corp/gocryptotrader/portfolio"
|
||||
)
|
||||
|
||||
func TestSetupPortfolioManager(t *testing.T) {
|
||||
@@ -94,3 +101,98 @@ func TestProcessPortfolio(t *testing.T) {
|
||||
|
||||
m.processPortfolio()
|
||||
}
|
||||
|
||||
func TestUpdateExchangeBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.ErrorContains(t, (*portfolioManager)(nil).updateExchangeBalances(), "nil pointer: *engine.portfolioManager")
|
||||
assert.ErrorIs(t, new(portfolioManager).updateExchangeBalances(), ErrNilSubsystem)
|
||||
|
||||
m, err := setupPortfolioManager(NewExchangeManager(), 0, &portfolio.Base{Verbose: true})
|
||||
require.NoError(t, err, "setupPortfolioManager must not error")
|
||||
assert.NoError(t, m.updateExchangeBalances(), "updateExchangeBalances should not error with an empty exchange list")
|
||||
|
||||
e := &mockExchange{err: errors.New("Mock UpdateBalanceError")}
|
||||
m.exchangeManager.exchanges = map[string]exchange.IBotExchange{"mock": e}
|
||||
assert.NoError(t, m.updateExchangeBalances(), "updateExchangeBalances should not error on disabled exchanges")
|
||||
|
||||
e.enabled = true
|
||||
assert.NoError(t, m.updateExchangeBalances(), "updateExchangeBalances should skip exchange without auth support")
|
||||
|
||||
e.authSupported = true
|
||||
assert.ErrorIs(t, m.updateExchangeBalances(), e.err, "error should contain the UpdateAccountBalances error message")
|
||||
}
|
||||
|
||||
func TestUpdateExchangeAddressBalances(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.ErrorContains(t, (*portfolioManager)(nil).updateExchangeAddressBalances(nil), "nil pointer: *engine.portfolioManager")
|
||||
assert.ErrorContains(t, new(portfolioManager).updateExchangeAddressBalances(nil), "nil pointer: <nil>")
|
||||
|
||||
e := &mockExchange{enabled: false, err: errors.New("Mock UpdateBalanceError")}
|
||||
m, err := setupPortfolioManager(NewExchangeManager(), 0, nil)
|
||||
require.NoError(t, err, "setupPortfolioManager must not error")
|
||||
assert.ErrorContains(t, m.updateExchangeAddressBalances(e), "nil pointer: *accounts.Accounts", "updateExchangeAddressBalances should propagate CurrencyBalances errors")
|
||||
|
||||
a := accounts.MustNewAccounts(e)
|
||||
e.accounts = a
|
||||
subAcct := accounts.NewSubAccount(asset.Spot, "")
|
||||
subAcct.Balances.Set(currency.BTC, accounts.Balance{Total: 1.5})
|
||||
subAcct.Balances.Set(currency.ETH, accounts.Balance{Total: 0})
|
||||
require.NoError(t, a.Save(t.Context(), accounts.SubAccounts{subAcct}, false), "accounts.Save must not error")
|
||||
require.NoError(t, m.updateExchangeAddressBalances(e))
|
||||
require.Len(t, m.base.Addresses, 1, "must have one address for the positive balance")
|
||||
assert.Equal(t, 1.5, m.base.Addresses[0].Balance, "balance should match on a new address")
|
||||
|
||||
subAcct.Balances.Set(currency.BTC, accounts.Balance{Total: 2})
|
||||
require.NoError(t, a.Save(t.Context(), accounts.SubAccounts{subAcct}, true), "accounts.Save must not error")
|
||||
require.NoError(t, m.updateExchangeAddressBalances(e))
|
||||
require.Len(t, m.base.Addresses, 1, "must have one address for the positive balance")
|
||||
assert.Equal(t, 2.0, m.base.Addresses[0].Balance, "balance should match after update existing address")
|
||||
|
||||
subAcct.Balances.Set(currency.BTC, accounts.Balance{Total: 0})
|
||||
require.NoError(t, a.Save(t.Context(), accounts.SubAccounts{subAcct}, true), "accounts.Save must not error")
|
||||
require.NoError(t, m.updateExchangeAddressBalances(e))
|
||||
assert.Empty(t, m.base.Addresses, "should have removed address with no balance")
|
||||
}
|
||||
|
||||
// mockExchange is a minimal mock for testing
|
||||
type mockExchange struct {
|
||||
exchange.IBotExchange
|
||||
enabled bool
|
||||
authSupported bool
|
||||
err error
|
||||
accounts *accounts.Accounts
|
||||
}
|
||||
|
||||
func (m *mockExchange) GetName() string {
|
||||
return "mocky"
|
||||
}
|
||||
|
||||
func (m *mockExchange) IsEnabled() bool {
|
||||
return m.enabled
|
||||
}
|
||||
|
||||
func (m *mockExchange) IsRESTAuthenticationSupported() bool {
|
||||
return m.authSupported
|
||||
}
|
||||
|
||||
func (m *mockExchange) HasAssetTypeAccountSegregation() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *mockExchange) GetAssetTypes(bool) asset.Items {
|
||||
return asset.Items{asset.Spot, asset.Futures}
|
||||
}
|
||||
|
||||
func (m *mockExchange) UpdateAccountBalances(context.Context, asset.Item) (accounts.SubAccounts, error) {
|
||||
return nil, m.err
|
||||
}
|
||||
|
||||
func (m *mockExchange) GetBase() *exchange.Base {
|
||||
return &exchange.Base{Name: "mocky", Accounts: m.accounts}
|
||||
}
|
||||
|
||||
func (m *mockExchange) GetCredentials(context.Context) (*accounts.Credentials, error) {
|
||||
return &accounts.Credentials{Key: m.GetName()}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user