Initial implementation of HTTP mock testing framework (#310)

* Initial implementation of HTTP mock testing framework

Convert to VCR testing server. Segregate live testing via build tags.

Converted Binance to VCR server

Convert Bitstamp to VCR mocking tests

Added VCR mock testing for localbitcoins

* Add server generation for concurrent testing

* Fix linter issues

* Fix linter issue

* fix race - potentially

* revert auto assigning of host vals

* Fix requested changes

* Adds mock testing for ANX
Switch to using TestMain functionality
Added cron job usage for travis-ci to live testing
Added appveyor scheduled build check for live testing

* WOOPS

* silly correction

* Fixes fantastic linter issues

* fixed another whoopsie

* WOOO!

* Adds gemini mock testing with additional fixes

* Add docs and sharedvalue

* Added tls using httptest package

* Fixed issues

* added explicit mock recording reference to error

* Fix requested changes

* strip port from mock files as they are not needed on tls server

* Change incorrect names

* fix requested changes

* lbank update

* Fix another issue

* Updated readme
This commit is contained in:
Ryan O'Hara-Reid
2019-08-23 15:20:02 +10:00
committed by Adrian Gallagher
parent a81ddead9e
commit 6d8ba0a96a
79 changed files with 109268 additions and 1250 deletions

View File

@@ -83,7 +83,7 @@ func (a *ANX) Setup(exch *config.ExchangeConfig) {
} else {
a.Enabled = true
a.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
a.SetAPIKeys(exch.APIKey, exch.APISecret, "", false)
a.SetAPIKeys(exch.APIKey, exch.APISecret, "", true)
a.SetHTTPClientTimeout(exch.HTTPTimeout)
a.SetHTTPClientUserAgent(exch.HTTPUserAgent)
a.RESTPollingDelay = exch.RESTPollingDelay
@@ -248,9 +248,13 @@ func (a *ANX) NewOrder(orderType string, buy bool, tradedCurrency string, traded
// CancelOrderByIDs cancels orders, requires already knowing order IDs
// There is no existing API call to retrieve orderIds
func (a *ANX) CancelOrderByIDs(orderIds []string) (OrderCancelResponse, error) {
var response OrderCancelResponse
if len(orderIds) == 0 {
return response, errors.New("no order ids provided")
}
req := make(map[string]interface{})
req["orderIds"] = orderIds
var response OrderCancelResponse
err := a.SendAuthenticatedHTTPRequest(anxOrderCancel, req, &response)
if response.ResultCode != "OK" {
@@ -266,7 +270,7 @@ func (a *ANX) GetOrderList(isActiveOrdersOnly bool) ([]OrderResponse, error) {
req["activeOnly"] = isActiveOrdersOnly
type OrderListResponse struct {
Timestamp int64 `json:"timestamp"`
Timestamp int64 `json:"timestamp,string"`
ResultCode string `json:"resultCode"`
Count int64 `json:"count"`
OrderResponses []OrderResponse `json:"orders"`
@@ -278,7 +282,6 @@ func (a *ANX) GetOrderList(isActiveOrdersOnly bool) ([]OrderResponse, error) {
}
if response.ResultCode != "OK" {
log.Errorf("Response code is not OK: %s\n", response.ResultCode)
return nil, errors.New(response.ResultCode)
}
@@ -304,7 +307,6 @@ func (a *ANX) OrderInfo(orderID string) (OrderResponse, error) {
}
if response.ResultCode != "OK" {
log.Errorf("Response code is not OK: %s\n", response.ResultCode)
return OrderResponse{}, errors.New(response.ResultCode)
}
return response.Order, nil
@@ -324,7 +326,7 @@ func (a *ANX) Send(currency, address, otp, amount string) (string, error) {
type SendResponse struct {
TransactionID string `json:"transactionId"`
ResultCode string `json:"resultCode"`
Timestamp int64 `json:"timestamp"`
Timestamp int64 `json:"timestamp,string"`
}
var response SendResponse
@@ -335,7 +337,6 @@ func (a *ANX) Send(currency, address, otp, amount string) (string, error) {
}
if response.ResultCode != "OK" {
log.Errorf("Response code is not OK: %s\n", response.ResultCode)
return "", errors.New(response.ResultCode)
}
return response.TransactionID, nil
@@ -361,7 +362,6 @@ func (a *ANX) CreateNewSubAccount(currency, name string) (string, error) {
}
if response.ResultCode != "OK" {
log.Errorf("Response code is not OK: %s\n", response.ResultCode)
return "", errors.New(response.ResultCode)
}
return response.SubAccount, nil
@@ -380,7 +380,7 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
Address string `json:"address"`
SubAccount string `json:"subAccount"`
ResultCode string `json:"resultCode"`
Timestamp int64 `json:"timestamp"`
Timestamp int64 `json:"timestamp,string"`
}
var response AddressResponse
@@ -395,7 +395,6 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
}
if response.ResultCode != "OK" {
log.Errorf("Response code is not OK: %s\n", response.ResultCode)
return "", errors.New(response.ResultCode)
}
@@ -404,7 +403,16 @@ func (a *ANX) GetDepositAddressByCurrency(currency, name string, newAddr bool) (
// SendHTTPRequest sends an unauthenticated HTTP request
func (a *ANX) SendHTTPRequest(path string, result interface{}) error {
return a.SendPayload(http.MethodGet, path, nil, nil, result, false, false, a.Verbose, a.HTTPDebugging)
return a.SendPayload(http.MethodGet,
path,
nil,
nil,
result,
false,
false,
a.Verbose,
a.HTTPDebugging,
a.HTTPRecording)
}
// SendAuthenticatedHTTPRequest sends a authenticated HTTP request
@@ -437,7 +445,16 @@ func (a *ANX) SendAuthenticatedHTTPRequest(path string, params map[string]interf
headers["Rest-Sign"] = common.Base64Encode(hmac)
headers["Content-Type"] = "application/json"
return a.SendPayload(http.MethodPost, a.APIUrl+path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose, a.HTTPDebugging)
return a.SendPayload(http.MethodPost,
a.APIUrl+path,
headers,
bytes.NewBuffer(PayloadJSON),
result,
true,
true,
a.Verbose,
a.HTTPDebugging,
a.HTTPRecording)
}
// GetFee returns an estimate of fee based on type of transaction

View File

@@ -0,0 +1,32 @@
//+build mock_test_off
// This will build if build tag mock_test_off is parsed and will do live testing
// using all tests in (exchange)_test.go
package anx
import (
"log"
"os"
"testing"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
)
var mockTests = false
func TestMain(m *testing.M) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
anxConfig, err := cfg.GetExchangeConfig("ANX")
if err != nil {
log.Fatalf("Test Failed - ANX Setup() init error", err)
}
anxConfig.AuthenticatedAPISupport = true
anxConfig.APIKey = apiKey
anxConfig.APISecret = apiSecret
a.SetDefaults()
a.Setup(&anxConfig)
log.Printf(sharedtestvalues.LiveTesting, a.GetName(), a.APIUrl)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,44 @@
//+build !mock_test_off
// This will build if build tag mock_test_off is not parsed and will try to mock
// all tests in _test.go
package anx
import (
"log"
"os"
"testing"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/exchanges/mock"
"github.com/thrasher-corp/gocryptotrader/exchanges/sharedtestvalues"
)
const mockFile = "../../testdata/http_mock/anx/anx.json"
var mockTests = true
func TestMain(m *testing.M) {
cfg := config.GetConfig()
cfg.LoadConfig("../../testdata/configtest.json")
anxConfig, err := cfg.GetExchangeConfig("ANX")
if err != nil {
log.Fatal("Test Failed - Mock server error", err)
}
anxConfig.AuthenticatedAPISupport = true
anxConfig.APIKey = apiKey
anxConfig.APISecret = apiSecret
a.SetDefaults()
a.Setup(&anxConfig)
serverDetails, newClient, err := mock.NewVCRServer(mockFile)
if err != nil {
log.Fatalf("Test Failed - Mock server error %s", err)
}
a.HTTPClient = newClient
a.APIUrl = serverDetails + "/"
log.Printf(sharedtestvalues.MockTesting, a.GetName(), a.APIUrl)
os.Exit(m.Run())
}

View File

@@ -4,7 +4,6 @@ import (
"testing"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/currency"
exchange "github.com/thrasher-corp/gocryptotrader/exchanges"
)
@@ -18,70 +17,8 @@ const (
var a ANX
func TestSetDefaults(t *testing.T) {
a.SetDefaults()
if a.Name != "ANX" {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if a.Enabled {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if a.TakerFee != 0.02 {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if a.MakerFee != 0.01 {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if a.Verbose {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if a.Websocket.IsEnabled() {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
if a.RESTPollingDelay != 10 {
t.Error("Test Failed - ANX SetDefaults() incorrect values set")
}
}
func TestSetup(t *testing.T) {
anxSetupConfig := config.GetConfig()
anxSetupConfig.LoadConfig("../../testdata/configtest.json")
anxConfig, err := anxSetupConfig.GetExchangeConfig("ANX")
anxConfig.AuthenticatedAPISupport = true
if err != nil {
t.Error("Test Failed - ANX Setup() init error")
}
a.Setup(&anxConfig)
a.APIKey = apiKey
a.APISecret = apiSecret
a.AuthenticatedAPISupport = true
if !a.Enabled {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if a.RESTPollingDelay != 10 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if a.Verbose {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if a.Websocket.IsEnabled() {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(a.BaseCurrencies) == 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(a.AvailablePairs) == 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
if len(a.EnabledPairs) == 0 {
t.Error("Test Failed - ANX Setup() incorrect values set")
}
}
func TestGetCurrencies(t *testing.T) {
t.Parallel()
_, err := a.GetCurrencies()
if err != nil {
t.Fatalf("Test failed. TestGetCurrencies failed. Err: %s", err)
@@ -89,6 +26,7 @@ func TestGetCurrencies(t *testing.T) {
}
func TestGetTradablePairs(t *testing.T) {
t.Parallel()
_, err := a.GetTradablePairs()
if err != nil {
t.Fatalf("Test failed. TestGetTradablePairs failed. Err: %s", err)
@@ -96,6 +34,7 @@ func TestGetTradablePairs(t *testing.T) {
}
func TestGetTicker(t *testing.T) {
t.Parallel()
ticker, err := a.GetTicker("BTCUSD")
if err != nil {
t.Errorf("Test Failed - ANX GetTicker() error: %s", err)
@@ -106,16 +45,18 @@ func TestGetTicker(t *testing.T) {
}
func TestGetDepth(t *testing.T) {
ticker, err := a.GetDepth("BTCUSD")
t.Parallel()
depth, err := a.GetDepth("BTCUSD")
if err != nil {
t.Errorf("Test Failed - ANX GetDepth() error: %s", err)
}
if ticker.Result != "success" {
if depth.Result != "success" {
t.Error("Test Failed - ANX GetDepth() unsuccessful")
}
}
func TestGetAPIKey(t *testing.T) {
t.Parallel()
apiKey, apiSecret, err := a.GetAPIKey("userName", "passWord", "", "1337")
if err == nil {
t.Error("Test Failed - ANX GetAPIKey() Incorrect")
@@ -140,6 +81,7 @@ func setFeeBuilder() *exchange.FeeBuilder {
// TestGetFeeByTypeOfflineTradeFee logic test
func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
t.Parallel()
var feeBuilder = setFeeBuilder()
a.GetFeeByType(feeBuilder)
if apiKey == "" || apiSecret == "" {
@@ -154,9 +96,7 @@ func TestGetFeeByTypeOfflineTradeFee(t *testing.T) {
}
func TestGetFee(t *testing.T) {
a.SetDefaults()
TestSetup(t)
t.Parallel()
var feeBuilder = setFeeBuilder()
// CryptocurrencyTradeFee Basic
@@ -226,7 +166,7 @@ func TestGetFee(t *testing.T) {
}
func TestFormatWithdrawPermissions(t *testing.T) {
a.SetDefaults()
t.Parallel()
expectedResult := exchange.AutoWithdrawCryptoWithSetupText + " & " + exchange.WithdrawCryptoWith2FAText + " & " +
exchange.WithdrawCryptoWithEmailText + " & " + exchange.WithdrawFiatViaWebsiteOnlyText
@@ -238,34 +178,36 @@ func TestFormatWithdrawPermissions(t *testing.T) {
}
func TestGetActiveOrders(t *testing.T) {
a.SetDefaults()
TestSetup(t)
t.Parallel()
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
}
_, err := a.GetActiveOrders(&getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
switch {
case areTestAPIKeysSet() && err != nil && !mockTests:
t.Errorf("Could not get open orders: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
case mockTests && err != nil:
t.Errorf("Could not get open orders: %s", err)
}
}
func TestGetOrderHistory(t *testing.T) {
a.SetDefaults()
TestSetup(t)
t.Parallel()
var getOrdersRequest = exchange.GetOrdersRequest{
OrderType: exchange.AnyOrderType,
}
_, err := a.GetOrderHistory(&getOrdersRequest)
if areTestAPIKeysSet() && err != nil {
switch {
case areTestAPIKeysSet() && err != nil && !mockTests:
t.Errorf("Could not get order history: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
case mockTests && err != nil:
t.Error("Test Failed - GetBalance() error", err)
}
}
@@ -281,10 +223,8 @@ func areTestAPIKeysSet() bool {
}
func TestSubmitOrder(t *testing.T) {
a.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Parallel()
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
var p = currency.Pair{
@@ -292,8 +232,9 @@ func TestSubmitOrder(t *testing.T) {
Base: currency.BTC,
Quote: currency.USD,
}
response, err := a.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "clientId")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) {
// TODO: QA Pass to submit order
response, err := a.SubmitOrder(p, exchange.BuyOrderSide, exchange.MarketOrderType, 1, 1, "")
if areTestAPIKeysSet() && (err != nil || !response.IsOrderPlaced) && !mockTests {
t.Errorf("Order failed to be placed: %v", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Expecting an error when no keys are set")
@@ -301,10 +242,8 @@ func TestSubmitOrder(t *testing.T) {
}
func TestCancelExchangeOrder(t *testing.T) {
a.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Parallel()
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
@@ -318,18 +257,19 @@ func TestCancelExchangeOrder(t *testing.T) {
}
err := a.CancelOrder(orderCancellation)
if areTestAPIKeysSet() && err != nil {
switch {
case areTestAPIKeysSet() && err != nil && !mockTests:
t.Errorf("Could not cancel order: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
case mockTests && err != nil:
t.Errorf("Could not cancel order: %s", err)
}
}
func TestCancelAllExchangeOrders(t *testing.T) {
a.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Parallel()
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
@@ -343,11 +283,13 @@ func TestCancelAllExchangeOrders(t *testing.T) {
}
resp, err := a.CancelAllOrders(orderCancellation)
if areTestAPIKeysSet() && err != nil {
switch {
case areTestAPIKeysSet() && err != nil && !mockTests:
t.Errorf("Could not cancel order: %s", err)
} else if !areTestAPIKeysSet() && err == nil {
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("Expecting an error when no keys are set")
case mockTests && err == nil:
t.Errorf("QA pass needs to be completed and mock needs to be updated error cannot be nil")
}
if len(resp.OrderStatus) > 0 {
@@ -356,20 +298,20 @@ func TestCancelAllExchangeOrders(t *testing.T) {
}
func TestGetAccountInfo(t *testing.T) {
if apiKey != "" || apiSecret != "" {
_, err := a.GetAccountInfo()
if err != nil {
t.Error("test failed - GetAccountInfo() error:", err)
}
} else {
_, err := a.GetAccountInfo()
if err == nil {
t.Error("test failed - GetAccountInfo() error")
}
t.Parallel()
_, err := a.GetAccountInfo()
switch {
case areTestAPIKeysSet() && err != nil && !mockTests:
t.Error("test failed - GetAccountInfo() error:", err)
case !areTestAPIKeysSet() && err == nil && !mockTests:
t.Error("test failed - GetAccountInfo() error")
case mockTests && err != nil:
t.Error("test failed - GetAccountInfo() error:", err)
}
}
func TestModifyOrder(t *testing.T) {
t.Parallel()
_, err := a.ModifyOrder(&exchange.ModifyOrder{})
if err == nil {
t.Error("Test failed - ModifyOrder() error")
@@ -377,10 +319,8 @@ func TestModifyOrder(t *testing.T) {
}
func TestWithdraw(t *testing.T) {
a.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Parallel()
if areTestAPIKeysSet() && !canManipulateRealOrders && !mockTests {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
@@ -393,61 +333,47 @@ func TestWithdraw(t *testing.T) {
}
_, err := a.WithdrawCryptocurrencyFunds(&withdrawCryptoRequest)
if areTestAPIKeysSet() && err != nil {
if areTestAPIKeysSet() && err != nil && !mockTests {
t.Errorf("Withdraw failed to be placed: %v", err)
} else if !areTestAPIKeysSet() && err == nil {
} else if !areTestAPIKeysSet() && err == nil && mockTests {
t.Error("Expecting an error when no keys are set")
}
}
func TestWithdrawFiat(t *testing.T) {
a.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
t.Parallel()
var withdrawFiatRequest = exchange.WithdrawRequest{}
_, err := a.WithdrawFiatFunds(&withdrawFiatRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
t.Errorf("Expected '%v', received: '%v'",
common.ErrFunctionNotSupported,
err)
}
}
func TestWithdrawInternationalBank(t *testing.T) {
a.SetDefaults()
TestSetup(t)
if areTestAPIKeysSet() && !canManipulateRealOrders {
t.Skip("API keys set, canManipulateRealOrders false, skipping test")
}
t.Parallel()
var withdrawFiatRequest = exchange.WithdrawRequest{}
_, err := a.WithdrawFiatFundsToInternationalBank(&withdrawFiatRequest)
if err != common.ErrFunctionNotSupported {
t.Errorf("Expected '%v', received: '%v'", common.ErrFunctionNotSupported, err)
t.Errorf("Expected '%v', received: '%v'",
common.ErrFunctionNotSupported,
err)
}
}
func TestGetDepositAddress(t *testing.T) {
if areTestAPIKeysSet() {
_, err := a.GetDepositAddress(currency.BTC, "")
if err != nil {
t.Error("Test Failed - GetDepositAddress() error", err)
}
} else {
_, err := a.GetDepositAddress(currency.BTC, "")
if err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}
t.Parallel()
_, err := a.GetDepositAddress(currency.BTC, "")
if areTestAPIKeysSet() && err != nil && !mockTests {
t.Error("Test Failed - GetDepositAddress() error", err)
} else if !areTestAPIKeysSet() && err == nil {
t.Error("Test Failed - GetDepositAddress() error cannot be nil")
}
}
func TestUpdateOrderbook(t *testing.T) {
a.SetDefaults()
t.Parallel()
q := currency.Pair{
Delimiter: "_",
Base: currency.BTC,