Files
gocryptotrader/exchanges/credentials_test.go
Ryan O'Hara-Reid 663e753f52 account: segregate holdings by credentials for future multi-key management (#956)
* exchanges/account: shift credentials to account package and segregate funds to keys

* merge: fixes

* linter: fix

* Update exchanges/account/account.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: nits + protection for string panic

* glorious_suggestion: add method for matching keys

* linter: fix tests

* account: add protected method for credentials minimizing access, display full account details to rpc.

* linter: spelling kweeeeeeen

* accounts/portfolio: clean/check portfolio code and quickly check balances from change. Add protected method for future matching.

* accounts: theres no point in pointerising everything

* linter: ok pointerise this then...

* exchanges: fix regression add in little notes.

* glorious: nits

* Update exchanges/account/credentials.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/account/credentials_test.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* Update exchanges/account/credentials_test.go

Co-authored-by: Scott <gloriousCode@users.noreply.github.com>

* glorious: nits

* gloriously: fix glorious glorious test gloriously

Co-authored-by: Ryan O'Hara-Reid <ryan.oharareid@thrasher.io>
Co-authored-by: Scott <gloriousCode@users.noreply.github.com>
2022-07-21 15:05:31 +10:00

362 lines
11 KiB
Go

package exchange
import (
"context"
"errors"
"testing"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/exchanges/account"
)
func TestGetCredentials(t *testing.T) {
t.Parallel()
var b Base
_, err := b.GetCredentials(context.Background())
if !errors.Is(err, ErrCredentialsAreEmpty) {
t.Fatalf("received: %v but expected: %v", err, ErrCredentialsAreEmpty)
}
b.API.CredentialsValidator.RequiresKey = true
ctx := account.DeployCredentialsToContext(context.Background(), &account.Credentials{Secret: "wow"})
_, err = b.GetCredentials(ctx)
if !errors.Is(err, errRequiresAPIKey) {
t.Fatalf("received: %v but expected: %v", err, errRequiresAPIKey)
}
b.API.CredentialsValidator.RequiresSecret = true
ctx = account.DeployCredentialsToContext(context.Background(), &account.Credentials{Key: "wow"})
_, err = b.GetCredentials(ctx)
if !errors.Is(err, errRequiresAPISecret) {
t.Fatalf("received: %v but expected: %v", err, errRequiresAPISecret)
}
ctx = context.WithValue(context.Background(), account.ContextCredentialsFlag, "pewpew")
_, err = b.GetCredentials(ctx)
if !errors.Is(err, errContextCredentialsFailure) {
t.Fatalf("received: %v but expected: %v", err, errContextCredentialsFailure)
}
fullCred := &account.Credentials{
Key: "superkey",
Secret: "supersecret",
SubAccount: "supersub",
ClientID: "superclient",
PEMKey: "superpem",
OneTimePassword: "superOneTimePasssssss",
}
ctx = account.DeployCredentialsToContext(context.Background(), fullCred)
creds, err := b.GetCredentials(ctx)
if !errors.Is(err, nil) {
t.Fatalf("received: %v but expected: %v", err, nil)
}
if creds.Key != "superkey" &&
creds.Secret != "supersecret" &&
creds.SubAccount != "supersub" &&
creds.ClientID != "superclient" &&
creds.PEMKey != "superpem" &&
creds.OneTimePassword != "superOneTimePasssssss" {
t.Fatal("unexpected values")
}
lonelyCred := &account.Credentials{
Key: "superkey",
Secret: "supersecret",
SubAccount: "supersub",
PEMKey: "superpem",
OneTimePassword: "superOneTimePasssssss",
}
ctx = account.DeployCredentialsToContext(context.Background(), lonelyCred)
b.API.CredentialsValidator.RequiresClientID = true
_, err = b.GetCredentials(ctx)
if !errors.Is(err, errRequiresAPIClientID) {
t.Fatalf("received: %v but expected: %v", err, errRequiresAPIClientID)
}
b.API.SetKey("hello")
b.API.SetSecret("sir")
b.API.SetClientID("1337")
ctx = context.WithValue(context.Background(), account.ContextSubAccountFlag, "superaccount")
overridedSA, err := b.GetCredentials(ctx)
if !errors.Is(err, nil) {
t.Fatalf("received: %v but expected: %v", err, nil)
}
if overridedSA.Key != "hello" &&
overridedSA.Secret != "sir" &&
overridedSA.ClientID != "1337" &&
overridedSA.SubAccount != "superaccount" {
t.Fatal("unexpected values")
}
notOverrided, err := b.GetCredentials(context.Background())
if !errors.Is(err, nil) {
t.Fatalf("received: %v but expected: %v", err, nil)
}
if notOverrided.Key != "hello" &&
notOverrided.Secret != "sir" &&
notOverrided.ClientID != "1337" &&
notOverrided.SubAccount != "" {
t.Fatal("unexpected values")
}
}
func TestAreCredentialsValid(t *testing.T) {
t.Parallel()
var b Base
if b.AreCredentialsValid(context.Background()) {
t.Fatal("should not be valid")
}
ctx := account.DeployCredentialsToContext(context.Background(), &account.Credentials{Key: "hello"})
if !b.AreCredentialsValid(ctx) {
t.Fatal("should be valid")
}
}
func TestValidateAPICredentials(t *testing.T) {
t.Parallel()
type tester struct {
Key string
Secret string
ClientID string
PEMKey string
RequiresPEM bool
RequiresKey bool
RequiresSecret bool
RequiresClientID bool
RequiresBase64DecodeSecret bool
Expected error
}
testCases := []tester{
// Empty credentials
{Expected: ErrCredentialsAreEmpty},
// test key
{RequiresKey: true, Expected: errRequiresAPIKey, Secret: "bruh"},
{RequiresKey: true, Key: "k3y"},
// test secret
{RequiresSecret: true, Expected: errRequiresAPISecret, Key: "bruh"},
{RequiresSecret: true, Secret: "s3cr3t"},
// test pem
{RequiresPEM: true, Expected: errRequiresAPIPEMKey, Key: "bruh"},
{RequiresPEM: true, PEMKey: "p3mK3y"},
// test clientID
{RequiresClientID: true, Expected: errRequiresAPIClientID, Key: "bruh"},
{RequiresClientID: true, ClientID: "cli3nt1D"},
// test requires base64 decode secret
{RequiresBase64DecodeSecret: true, RequiresSecret: true, Expected: errRequiresAPISecret, Key: "bruh"},
{RequiresBase64DecodeSecret: true, Secret: "%%", Expected: errBase64DecodeFailure},
{RequiresBase64DecodeSecret: true, Secret: "aGVsbG8gd29ybGQ="},
}
setupBase := func(tData *tester) *Base {
b := &Base{}
b.API.SetKey(tData.Key)
b.API.SetSecret(tData.Secret)
b.API.SetClientID(tData.ClientID)
b.API.SetPEMKey(tData.PEMKey)
b.API.CredentialsValidator.RequiresKey = tData.RequiresKey
b.API.CredentialsValidator.RequiresSecret = tData.RequiresSecret
b.API.CredentialsValidator.RequiresPEM = tData.RequiresPEM
b.API.CredentialsValidator.RequiresClientID = tData.RequiresClientID
b.API.CredentialsValidator.RequiresBase64DecodeSecret = tData.RequiresBase64DecodeSecret
return b
}
for x := range testCases {
testData := &testCases[x]
t.Run("", func(t *testing.T) {
t.Parallel()
b := setupBase(testData)
if err := b.ValidateAPICredentials(b.API.credentials); !errors.Is(err, testData.Expected) {
t.Errorf("Test %d: expected: %v: got %v", x+1, testData.Expected, err)
}
})
}
}
func TestCheckCredentials(t *testing.T) {
t.Parallel()
b := Base{
SkipAuthCheck: true,
API: API{credentials: &account.Credentials{}},
}
// Test SkipAuthCheck
err := b.CheckCredentials(&account.Credentials{}, false)
if !errors.Is(err, nil) {
t.Errorf("received '%v' expected '%v'", err, nil)
}
// Test credentials failure
b.SkipAuthCheck = false
b.API.CredentialsValidator.RequiresKey = true
b.API.credentials.OneTimePassword = "wow"
err = b.CheckCredentials(b.API.credentials, false)
if !errors.Is(err, errRequiresAPIKey) {
t.Errorf("received '%v' expected '%v'", err, errRequiresAPIKey)
}
b.API.credentials.OneTimePassword = ""
// Test bot usage with authenticated API support disabled, but with
// valid credentials
b.LoadedByConfig = true
b.API.credentials.Key = "k3y"
err = b.CheckCredentials(b.API.credentials, false)
if !errors.Is(err, ErrAuthenticationSupportNotEnabled) {
t.Errorf("received '%v' expected '%v'", err, ErrAuthenticationSupportNotEnabled)
}
// Test enabled authenticated API support and loaded by config
// but invalid credentials
b.API.AuthenticatedSupport = true
b.API.credentials.Key = ""
err = b.CheckCredentials(b.API.credentials, false)
if !errors.Is(err, ErrCredentialsAreEmpty) {
t.Errorf("received '%v' expected '%v'", err, ErrCredentialsAreEmpty)
}
// Finally a valid one
b.API.credentials.Key = "k3y"
err = b.CheckCredentials(b.API.credentials, false)
if !errors.Is(err, nil) {
t.Errorf("received '%v' expected '%v'", err, nil)
}
}
func TestAPISetters(t *testing.T) {
t.Parallel()
api := API{}
api.SetKey(account.Key)
if api.credentials.Key != account.Key {
t.Fatal("unexpected value")
}
api = API{}
api.SetSecret(account.Secret)
if api.credentials.Secret != account.Secret {
t.Fatal("unexpected value")
}
api = API{}
api.SetClientID(account.ClientID)
if api.credentials.ClientID != account.ClientID {
t.Fatal("unexpected value")
}
api = API{}
api.SetPEMKey(account.PEMKey)
if api.credentials.PEMKey != account.PEMKey {
t.Fatal("unexpected value")
}
api = API{}
api.SetSubAccount(account.SubAccountSTR)
if api.credentials.SubAccount != account.SubAccountSTR {
t.Fatal("unexpected value")
}
}
func TestSetCredentials(t *testing.T) {
t.Parallel()
b := Base{
Name: "TESTNAME",
Enabled: false,
API: API{
AuthenticatedSupport: false,
AuthenticatedWebsocketSupport: false,
},
}
b.SetCredentials("RocketMan", "Digereedoo", "007", "", "", "")
if b.API.credentials.Key != "RocketMan" &&
b.API.credentials.Secret != "Digereedoo" &&
b.API.credentials.ClientID != "007" {
t.Error("invalid API credentials")
}
// Invalid secret
b.API.CredentialsValidator.RequiresBase64DecodeSecret = true
b.API.AuthenticatedSupport = true
b.SetCredentials("RocketMan", "%%", "007", "", "", "")
if b.API.AuthenticatedSupport || b.API.AuthenticatedWebsocketSupport {
t.Error("invalid secret should disable authenticated API support")
}
// valid secret
b.API.CredentialsValidator.RequiresBase64DecodeSecret = true
b.API.AuthenticatedSupport = true
b.SetCredentials("RocketMan", "aGVsbG8gd29ybGQ=", "007", "", "", "")
if !b.API.AuthenticatedSupport && b.API.credentials.Secret != "hello world" {
t.Error("invalid secret should disable authenticated API support")
}
}
func TestGetDefaultCredentials(t *testing.T) {
var b Base
if b.GetDefaultCredentials() != nil {
t.Fatal("unexpected return")
}
b.SetCredentials("test", "", "", "", "", "")
if b.GetDefaultCredentials() == nil {
t.Fatal("unexpected return")
}
}
func TestSetAPICredentialDefaults(t *testing.T) {
t.Parallel()
b := Base{
Config: &config.Exchange{},
}
b.API.CredentialsValidator.RequiresKey = true
b.API.CredentialsValidator.RequiresSecret = true
b.API.CredentialsValidator.RequiresBase64DecodeSecret = true
b.API.CredentialsValidator.RequiresClientID = true
b.API.CredentialsValidator.RequiresPEM = true
b.SetAPICredentialDefaults()
if !b.Config.API.CredentialsValidator.RequiresKey ||
!b.Config.API.CredentialsValidator.RequiresSecret ||
!b.Config.API.CredentialsValidator.RequiresBase64DecodeSecret ||
!b.Config.API.CredentialsValidator.RequiresClientID ||
!b.Config.API.CredentialsValidator.RequiresPEM {
t.Error("incorrect values")
}
}
// TestGetAuthenticatedAPISupport logic test
func TestGetAuthenticatedAPISupport(t *testing.T) {
t.Parallel()
base := Base{
API: API{
AuthenticatedSupport: true,
AuthenticatedWebsocketSupport: false,
},
}
if !base.IsRESTAuthenticationSupported() {
t.Fatal("Expected RestAuthentication to return true")
}
base.API.AuthenticatedSupport = false
if base.IsRESTAuthenticationSupported() {
t.Fatal("Expected RestAuthentication to return false")
}
if base.IsWebsocketAuthenticationSupported() {
t.Fatal("Expected WebsocketAuthentication to return false")
}
base.API.AuthenticatedWebsocketSupport = true
if !base.IsWebsocketAuthenticationSupported() {
t.Fatal("Expected WebsocketAuthentication to return true")
}
}