Skip to content

Commit

Permalink
Initial implementation of HTTP mock testing framework (thrasher-corp#310
Browse files Browse the repository at this point in the history
)

* 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
  • Loading branch information
shazbert authored and thrasher- committed Aug 23, 2019
1 parent a81ddea commit 6d8ba0a
Show file tree
Hide file tree
Showing 79 changed files with 109,267 additions and 1,249 deletions.
7 changes: 6 additions & 1 deletion .appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ test_script:
# test back-end
- go get github.com/golangci/golangci-lint/cmd/[email protected]
- '%GOPATH%\bin\golangci-lint.exe run --verbose'
- go test -race ./...
- ps: >-
if($env:APPVEYOR_SCHEDULED_BUILD -eq 'true') {
go test -race ./... -tags=mock_test_off
}else {
go test -race ./...
}
# test front-end
- node --version
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ LINTPKG = github.com/golangci/golangci-lint/cmd/[email protected]
LINTBIN = $(GOPATH)/bin/golangci-lint
GCTLISTENPORT=9050
GCTPROFILERLISTENPORT=8085
CRON = $(TRAVIS_EVENT_TYPE)

get:
GO111MODULE=on go get $(GCTPKG)
Expand All @@ -16,7 +17,11 @@ linter:
check: linter test

test:
ifeq ($(CRON), cron)
go test -race -tags=mock_test_off -coverprofile=coverage.txt -covermode=atomic ./...
else
go test -race -coverprofile=coverage.txt -covermode=atomic ./...
endif

build:
GO111MODULE=on go build $(LDFLAGS)
Expand Down
1 change: 1 addition & 0 deletions currency/coinmarketcap/coinmarketcap.go
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,7 @@ func (c *Coinmarketcap) SendHTTPRequest(method, endpoint string, v url.Values, r
false,
false,
c.Verbose,
false,
false)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ func (c *CurrencyConverter) SendHTTPRequest(endPoint string, values url.Values,
auth,
false,
c.Verbose,
false,
false)
if err != nil {
return fmt.Errorf("currency converter API SendHTTPRequest error %s with path %s",
Expand Down
1 change: 1 addition & 0 deletions currency/forexprovider/currencylayer/currencylayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,6 @@ func (c *CurrencyLayer) SendHTTPRequest(endPoint string, values url.Values, resu
auth,
false,
c.Verbose,
false,
false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func (e *ExchangeRates) SendHTTPRequest(endPoint string, values url.Values, resu
false,
false,
e.Verbose,
false,
false)
if err != nil {
return fmt.Errorf("exchangeRatesAPI SendHTTPRequest error %s with path %s",
Expand Down
1 change: 1 addition & 0 deletions currency/forexprovider/fixer.io/fixer.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,6 @@ func (f *Fixer) SendOpenHTTPRequest(endpoint string, v url.Values, result interf
auth,
false,
f.Verbose,
false,
false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -265,5 +265,6 @@ func (o *OXR) SendHTTPRequest(endpoint string, values url.Values, result interfa
false,
false,
o.Verbose,
false,
false)
}
22 changes: 20 additions & 2 deletions exchanges/alphapoint/alphapoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,16 @@ func (a *Alphapoint) SendHTTPRequest(method, path string, data map[string]interf
return errors.New("unable to JSON request")
}

return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, false, false, a.Verbose, a.HTTPDebugging)
return a.SendPayload(method,
path,
headers,
bytes.NewBuffer(PayloadJSON),
result,
false,
false,
a.Verbose,
a.HTTPDebugging,
a.HTTPRecording)
}

// SendAuthenticatedHTTPRequest sends an authenticated request
Expand All @@ -559,5 +568,14 @@ func (a *Alphapoint) SendAuthenticatedHTTPRequest(method, path string, data map[
return errors.New("unable to JSON request")
}

return a.SendPayload(method, path, headers, bytes.NewBuffer(PayloadJSON), result, true, true, a.Verbose, a.HTTPDebugging)
return a.SendPayload(method,
path,
headers,
bytes.NewBuffer(PayloadJSON),
result,
true,
true,
a.Verbose,
a.HTTPDebugging,
a.HTTPRecording)
}
41 changes: 29 additions & 12 deletions exchanges/anx/anx.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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" {
Expand All @@ -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"`
Expand All @@ -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)
}

Expand All @@ -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
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -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)
}

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions exchanges/anx/anx_live_test.go
Original file line number Diff line number Diff line change
@@ -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())
}
44 changes: 44 additions & 0 deletions exchanges/anx/anx_mock_test.go
Original file line number Diff line number Diff line change
@@ -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())
}
Loading

0 comments on commit 6d8ba0a

Please sign in to comment.