exchanges: Limit mock test JSON data size by truncating slices and maps (#1968)

* set limiter to first level mock data list and updated unit tests

* address nested slices length limit

* minor fix recording file and update unit tests

* minor updates on unit tests

* re-record mock files and minor fix on the unit tests ti adapt the mock data change

* improve http recording limit value and fix issues with mock data in binance

* added MockDataSliceLimit in request items and resolve minor unit test issues

* resolve missed conflict

* rename mock variables, resolve unit test issues, and other updates

* minor fix to CheckJSON and update unit tests

* minor unit test fix

* further optimization on mock CheckJSON method, unit tests, and re-record poloniex

* common and recording unit tests fix

* minor linter issues fix

* unit tests format fix

* fix miscellaneous error

* unit tests fix and minor docs update

* re-record and reduce mock file size

* indentation fix

* minor assertion test fix

* reverted log.Printf line in live testing

* rename variables

* update NewVCRServer unit test

* replace string comparison with *net.OpError check

* restructur net error test

* exchanges/mock: Remove redundant error assertion message in TestNewVCRServer

---------

Co-authored-by: Adrian Gallagher <adrian.gallagher@thrasher.io>
This commit is contained in:
Samuael A.
2025-08-26 03:27:07 +03:00
committed by GitHub
parent 370666cd21
commit fc0f262c42
47 changed files with 11143 additions and 503139 deletions

View File

@@ -4,10 +4,13 @@ import (
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
)
func TestMatchURLVals(t *testing.T) {
t.Parallel()
testVal, testVal2, testVal3, emptyVal := url.Values{}, url.Values{}, url.Values{}, url.Values{}
testVal.Add("test", "test")
testVal2.Add("test2", "test2")
@@ -17,87 +20,39 @@ func TestMatchURLVals(t *testing.T) {
nonceVal1.Add("nonce", "012349723587")
nonceVal2.Add("nonce", "9327373874")
expected := false
received := MatchURLVals(testVal, emptyVal)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
tests := []struct {
a url.Values
b url.Values
exp bool
}{
{testVal, emptyVal, false},
{emptyVal, testVal, false},
{testVal, testVal2, false},
{testVal2, testVal, false},
{testVal, testVal3, false},
{nonceVal1, testVal2, false},
{emptyVal, emptyVal, true},
{testVal, testVal, true},
{nonceVal1, nonceVal2, true},
}
received = MatchURLVals(emptyVal, testVal)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
received = MatchURLVals(testVal, testVal2)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
received = MatchURLVals(testVal2, testVal)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
received = MatchURLVals(testVal, testVal3)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
received = MatchURLVals(nonceVal1, testVal2)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
expected = true
received = MatchURLVals(emptyVal, emptyVal)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
received = MatchURLVals(testVal, testVal)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
}
received = MatchURLVals(nonceVal1, nonceVal2)
if received != expected {
t.Errorf("MatchURLVals error expected %v received %v",
expected,
received)
for _, tc := range tests {
got := MatchURLVals(tc.a, tc.b)
assert.Equalf(t, tc.exp, got, "MatchURLVals should return correctly for (%q, %q)", tc.a, tc.b)
}
}
func TestDeriveURLValsFromJSON(t *testing.T) {
type class struct {
Numbers []int `json:"numbers"`
Number float64 `json:"number"`
SomeString string `json:"somestring"`
}
test1 := struct {
Things []string `json:"things"`
Data struct {
Numbers []int `json:"numbers"`
Number float64 `json:"number"`
SomeString string `json:"somestring"`
} `json:"data"`
Data class `json:"data"`
}{
Things: []string{"hello", "world"},
Data: struct {
Numbers []int `json:"numbers"`
Number float64 `json:"number"`
SomeString string `json:"somestring"`
}{
Data: class{
Numbers: []int{1, 3, 3, 7},
Number: 3.14,
SomeString: "hello, peoples",
@@ -105,14 +60,11 @@ func TestDeriveURLValsFromJSON(t *testing.T) {
}
payload, err := json.Marshal(test1)
if err != nil {
t.Error("marshal error", err)
}
require.NoError(t, err, "Marshal must not error")
_, err = DeriveURLValsFromJSONMap(payload)
if err != nil {
t.Error("DeriveURLValsFromJSON error", err)
}
values, err := DeriveURLValsFromJSONMap(payload)
assert.NoError(t, err, "DeriveURLValsFromJSONMap should not error")
assert.Len(t, values, 2)
test2 := map[string]string{
"val": "1",
@@ -125,17 +77,13 @@ func TestDeriveURLValsFromJSON(t *testing.T) {
}
payload, err = json.Marshal(test2)
if err != nil {
t.Error("marshal error", err)
}
require.NoError(t, err, "Marshal must not error")
vals, err := DeriveURLValsFromJSONMap(payload)
if err != nil {
t.Error("DeriveURLValsFromJSON error", err)
}
if vals["val"][0] != "1" {
t.Error("DeriveURLValsFromJSON unexpected value",
vals["val"][0])
values, err = DeriveURLValsFromJSONMap(payload)
require.NoError(t, err, "DeriveURLValsFromJSONMap must not error")
require.Equal(t, 7, len(values), "DeriveURLValsFromJSONMap must return the correct number of values")
for key, val := range values {
require.Len(t, val, 1)
assert.Equalf(t, test2[key], val[0], "DeriveURLValsFromJSON should return the correct value for %s", key)
}
}

View File

@@ -19,6 +19,9 @@ import (
"github.com/thrasher-corp/gocryptotrader/encoding/json"
)
// defaultDataSliceLimit the mock slice data size limit to a default of 5
const defaultDataSliceLimit = 5
// HTTPResponse defines expected response from the end point including request
// data for pathing on the VCR server
type HTTPResponse struct {
@@ -30,7 +33,8 @@ type HTTPResponse struct {
// HTTPRecord will record the request and response to a default JSON file for
// mocking purposes
func HTTPRecord(res *http.Response, service string, respContents []byte) error {
// mockDataSliceLimit defaults to 5
func HTTPRecord(res *http.Response, service string, respContents []byte, mockDataSliceLimit int) error {
if res == nil {
return errors.New("http.Response cannot be nil")
}
@@ -47,7 +51,9 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
return errors.New("service not supplied cannot access correct mock file")
}
service = strings.ToLower(service)
if mockDataSliceLimit == 0 {
mockDataSliceLimit = defaultDataSliceLimit
}
outputFilePath := filepath.Join(DefaultDirectory, service, service+".json")
_, err := os.Stat(outputFilePath)
if err != nil {
@@ -77,8 +83,13 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
m.Routes = make(map[string]map[string][]HTTPResponse)
}
items, err := getExcludedItems()
if err != nil {
return err
}
var httpResponse HTTPResponse
cleanedContents, err := CheckResponsePayload(respContents)
cleanedContents, err := CheckResponsePayload(respContents, items, mockDataSliceLimit)
if err != nil {
return err
}
@@ -108,11 +119,7 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
return urlErr
}
httpResponse.BodyParams, urlErr = GetFilteredURLVals(vals)
if urlErr != nil {
return urlErr
}
httpResponse.BodyParams = GetFilteredURLVals(vals, items)
case textPlain:
payload := res.Request.Header.Get("X-Gemini-Payload")
j, dErr := base64.StdEncoding.DecodeString(payload)
@@ -126,15 +133,8 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
httpResponse.BodyParams = body
}
httpResponse.Headers, err = GetFilteredHeader(res)
if err != nil {
return err
}
httpResponse.QueryString, err = GetFilteredURLVals(res.Request.URL.Query())
if err != nil {
return err
}
httpResponse.Headers = GetFilteredHeader(res, items)
httpResponse.QueryString = GetFilteredURLVals(res.Request.URL.Query(), items)
_, ok := m.Routes[res.Request.URL.Path]
if !ok {
@@ -245,54 +245,37 @@ func HTTPRecord(res *http.Response, service string, respContents []byte) error {
// GetFilteredHeader filters excluded http headers for insertion into a mock
// test file
func GetFilteredHeader(res *http.Response) (http.Header, error) {
items, err := GetExcludedItems()
if err != nil {
return res.Header, err
}
func GetFilteredHeader(res *http.Response, items Exclusion) http.Header {
for i := range items.Headers {
if res.Request.Header.Get(items.Headers[i]) != "" {
res.Request.Header.Set(items.Headers[i], "")
}
}
return res.Request.Header, nil
return res.Request.Header
}
// GetFilteredURLVals filters excluded url value variables for insertion into a
// mock test file
func GetFilteredURLVals(vals url.Values) (string, error) {
items, err := GetExcludedItems()
if err != nil {
return "", err
}
for key, val := range vals {
func GetFilteredURLVals(vals url.Values, items Exclusion) string {
for key := range vals {
for i := range items.Variables {
if strings.EqualFold(items.Variables[i], val[0]) {
if strings.EqualFold(items.Variables[i], key) {
vals.Set(key, "")
}
}
}
return vals.Encode(), nil
return vals.Encode()
}
// CheckResponsePayload checks to see if there are any response body variables
// that should not be there.
func CheckResponsePayload(data []byte) ([]byte, error) {
items, err := GetExcludedItems()
if err != nil {
return nil, err
}
func CheckResponsePayload(data []byte, items Exclusion, mockDataSliceLimit int) ([]byte, error) {
var intermediary any
err = json.Unmarshal(data, &intermediary)
if err != nil {
if err := json.Unmarshal(data, &intermediary); err != nil {
return nil, err
}
payload, err := CheckJSON(intermediary, &items)
payload, err := CheckJSON(intermediary, &items, mockDataSliceLimit)
if err != nil {
return nil, err
}
@@ -302,7 +285,6 @@ func CheckResponsePayload(data []byte) ([]byte, error) {
// Reflection consts
const (
Int64 = "int64"
Float64 = "float64"
Slice = "slice"
String = "string"
@@ -311,22 +293,23 @@ const (
)
// CheckJSON recursively parses json data to retract keywords, quite intensive.
func CheckJSON(data any, excluded *Exclusion) (any, error) {
if d, ok := data.([]any); ok {
func CheckJSON(data any, excluded *Exclusion, limit int) (any, error) {
if value, ok := data.([]any); ok {
var sData []any
for i := range d {
v := d[i]
switch v.(type) {
case map[string]any, []any:
checkedData, err := CheckJSON(v, excluded)
for i := range value {
switch subvalue := value[i].(type) {
case []any, map[string]any:
checkedData, err := CheckJSON(subvalue, excluded, limit)
if err != nil {
return nil, err
}
sData = append(sData, checkedData)
if limit > 0 && len(sData) >= limit {
return sData, nil
}
default:
// Primitive value doesn't need exclusions applied, e.g. float64 or string
sData = append(sData, v)
sData = append(sData, subvalue)
}
}
return sData, nil
@@ -337,67 +320,55 @@ func CheckJSON(data any, excluded *Exclusion) (any, error) {
return nil, err
}
var context map[string]any
err = json.Unmarshal(conv, &context)
var contextValue map[string]any
err = json.Unmarshal(conv, &contextValue)
if err != nil {
return nil, err
}
if len(context) == 0 {
if len(contextValue) == 0 {
// Nil for some reason, should error out before in json.Unmarshal
return nil, nil
return contextValue, nil
}
for key, val := range context {
for key, val := range contextValue {
switch reflect.ValueOf(val).Kind().String() {
case String:
if IsExcluded(key, excluded.Variables) {
context[key] = "" // Zero val string
}
case Int64:
if IsExcluded(key, excluded.Variables) {
context[key] = 0 // Zero val int
contextValue[key] = "" // Zero val string
}
case Float64:
if IsExcluded(key, excluded.Variables) {
context[key] = 0.0 // Zero val float
contextValue[key] = 0.0 // Zero val float
}
case Slice:
slice, ok := val.([]any)
if !ok {
return nil, common.GetTypeAssertError("[]any", val)
}
if len(slice) < 1 {
switch {
case len(slice) == 0:
// Empty slice found
context[key] = slice
} else {
if _, ok := slice[0].(map[string]any); ok {
var cleanSlice []any
for i := range slice {
cleanMap, sErr := CheckJSON(slice[i], excluded)
if sErr != nil {
return nil, sErr
}
cleanSlice = append(cleanSlice, cleanMap)
}
context[key] = cleanSlice
} else if IsExcluded(key, excluded.Variables) {
context[key] = nil // Zero val slice
contextValue[key] = slice
case IsExcluded(key, excluded.Variables):
contextValue[key] = nil // Zero val slice
default:
contextValue[key], err = CheckJSON(slice, excluded, limit)
if err != nil {
return nil, err
}
}
case Bool, Invalid: // Skip these bad boys for now
default:
// Recursively check map data
contextValue, err := CheckJSON(val, excluded)
contextValue[key], err = CheckJSON(val, excluded, limit)
if err != nil {
return nil, err
}
context[key] = contextValue
}
}
return context, nil
return contextValue, nil
}
// IsExcluded cross references the key with the excluded variables
@@ -443,9 +414,9 @@ type Exclusion struct {
Variables []string `json:"variables"`
}
// GetExcludedItems checks to see if the variable is in the exclusion list as to
// getExcludedItems checks to see if the variable is in the exclusion list as to
// not display secure items in mock file generator output
func GetExcludedItems() (Exclusion, error) {
func getExcludedItems() (Exclusion, error) {
m.Lock()
defer m.Unlock()
if !set {

View File

@@ -3,39 +3,38 @@ package mock
import (
"net/http"
"net/url"
"strings"
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
)
func TestGetFilteredHeader(t *testing.T) {
items, err := getExcludedItems()
require.NoError(t, err, "getExcludedItems must not error")
assert.NotNil(t, items, "getExcludedItems should not return nil")
resp := http.Response{}
resp.Request = &http.Request{}
resp.Request.Header = http.Header{}
resp.Request.Header.Set("Key", "RiskyVals")
fMap, err := GetFilteredHeader(&resp)
if err != nil {
t.Error(err)
}
if fMap.Get("Key") != "" {
t.Error("risky vals where not replaced correctly")
}
fMap := GetFilteredHeader(&resp, items)
assert.Empty(t, fMap.Get("Key"), "risky values should be removed")
}
func TestGetFilteredURLVals(t *testing.T) {
items, err := getExcludedItems()
require.NoError(t, err, "getExcludedItems must not error")
assert.NotNil(t, items, "getExcludedItems should not return nil")
superSecretData := "Dr Seuss"
shadyVals := url.Values{}
shadyVals.Set("real_name", superSecretData)
cleanVals, err := GetFilteredURLVals(shadyVals)
if err != nil {
t.Error("GetFilteredURLVals error", err)
}
if strings.Contains(cleanVals, superSecretData) {
t.Error("Super secret data found")
}
cleanVals := GetFilteredURLVals(shadyVals, items)
assert.NotContains(t, cleanVals, superSecretData, "exclusion real_name should be removed")
}
func TestCheckResponsePayload(t *testing.T) {
@@ -46,22 +45,26 @@ func TestCheckResponsePayload(t *testing.T) {
}
payload, err := json.Marshal(testbody)
if err != nil {
t.Fatal("json marshal error", err)
}
require.NoError(t, err, "json marshal must not error")
data, err := CheckResponsePayload(payload)
if err != nil {
t.Error("CheckBody error", err)
}
items, err := getExcludedItems()
require.NoError(t, err, "getExcludedItems must not error")
assert.NotNil(t, items, "getExcludedItems should not return nil")
data, err := CheckResponsePayload(payload, items, 5)
assert.NoError(t, err, "CheckResponsePayload should not error")
expected := `{
"stuff": "REAAAAHHHHH"
}`
assert.Equal(t, expected, string(data))
}
if string(data) != expected {
t.Error("unexpected returned data")
}
func TestGetExcludedItems(t *testing.T) {
exclusionList, err := getExcludedItems()
require.NoError(t, err, "getExcludedItems must not error")
assert.NotEmpty(t, exclusionList.Headers, "Headers should not be empty")
assert.NotEmpty(t, exclusionList.Variables, "Variables should not be empty")
}
type TestStructLevel0 struct {
@@ -81,130 +84,123 @@ type TestStructLevel1 struct {
}
type TestStructLevel2 struct {
OkayVal string `json:"okayVal"`
OkayVal2 float64 `json:"okayVal2"`
BadVal float32 `json:"name"`
BadVal2 int32 `json:"real_name"`
OtherData TestStructLevel3 `json:"moreOtherVals"`
OkayVal string `json:"okayVal"`
OkayVal2 float64 `json:"okayVal2"`
OkayVal3 map[string]any `json:"okayVal3"`
OkayVal4 map[string]any `json:"okayVal4"`
OkayVal5 []any `json:"okayVal5"`
BadVal int64 `json:"receiver_name"`
BadVal2 string `json:"account_number"`
BadVal3 []any `json:"secret"`
}
type TestStructLevel3 struct {
OkayVal string `json:"okayVal"`
OkayVal2 float64 `json:"okayVal2"`
BadVal int64 `json:"receiver_name"`
BadVal2 string `json:"account_number"`
var testVal = []TestStructLevel0{
{
StringVal: "somestringstuff",
FloatVal: 3.14,
IntVal: 1337,
StructVal: TestStructLevel1{
OkayVal: "stuff",
OkayVal2: 120938,
BadVal: "CritcalBankingStuff",
BadVal2: 1337,
OtherData: TestStructLevel2{
OkayVal: "stuff",
OkayVal2: 129219809899009009080980,
OkayVal3: map[string]any{"a": 1},
OkayVal4: map[string]any{},
OkayVal5: []any{},
BadVal: 1337,
BadVal2: "Super Secret Password",
BadVal3: []any{123, 'a'},
},
},
MixedSlice: []any{
[]map[string]any{{"id": 0}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}, {"id": 6}, {}},
[]any{float64(1586994000000), "6615.23000000", 'a', 1234, false, int64(17866372632), 0},
"abcd",
},
},
{
StringVal: "somestringstuff",
FloatVal: 3.14,
},
{
StringVal: "somestringstuff",
FloatVal: 3.14,
IntVal: 1337,
},
{
StringVal: "somestringstuff",
IntVal: 1337,
},
{},
{},
{},
}
func TestCheckJSON(t *testing.T) {
level3 := TestStructLevel3{
OkayVal: "stuff",
OkayVal2: 129219,
BadVal: 1337,
BadVal2: "Super Secret Password",
}
exclusionList, err := getExcludedItems()
require.NoError(t, err, "getExcludedItems must not error")
assert.NotNil(t, exclusionList, "getExcludedItems should not return nil")
level2 := TestStructLevel2{
OkayVal: "stuff",
OkayVal2: 129219,
BadVal: 0.222,
BadVal2: 1337888888,
OtherData: level3,
}
data, err := json.Marshal(testVal)
require.NoError(t, err, "Marshal must not error")
require.NotNil(t, data, "Marshal must not return nil")
level1 := TestStructLevel1{
OkayVal: "stuff",
OkayVal2: 120938,
BadVal: "CritcalBankingStuff",
BadVal2: 1337,
OtherData: level2,
}
var input any
err = json.Unmarshal(data, &input)
require.NoError(t, err, "Unmarshal must not error")
sliceOfPrimitives := []any{
[]any{float64(1586994000000), "6615.23000000"},
[]any{float64(1586994300000), "6624.74000000"},
}
testVal := TestStructLevel0{
StringVal: "somestringstuff",
FloatVal: 3.14,
IntVal: 1337,
StructVal: level1,
MixedSlice: sliceOfPrimitives,
}
exclusionList, err := GetExcludedItems()
if err != nil {
t.Error("GetExcludedItems error", err)
}
vals, err := CheckJSON(testVal, &exclusionList)
if err != nil {
t.Error("Check JSON error", err)
}
vals, err := CheckJSON(input, &exclusionList, 4)
assert.NoError(t, err, "CheckJSON should not error")
payload, err := json.Marshal(vals)
if err != nil {
t.Fatal("json marshal error", err)
}
require.NoError(t, err, "Marshal must not error")
newStruct := TestStructLevel0{}
newStruct := []TestStructLevel0{}
err = json.Unmarshal(payload, &newStruct)
if err != nil {
t.Fatal("Umarshal error", err)
}
require.NoError(t, err, "Umarshal must not error")
if newStruct.StructVal.BadVal != "" {
t.Error("Value not wiped correctly")
}
if newStruct.StructVal.BadVal2 != 0 {
t.Error("Value not wiped correctly")
}
if newStruct.StructVal.OtherData.BadVal != 0 {
t.Error("Value not wiped correctly")
}
if newStruct.StructVal.OtherData.BadVal2 != 0 {
t.Error("Value not wiped correctly")
}
if newStruct.StructVal.OtherData.OtherData.BadVal != 0 {
t.Error("Value not wiped correctly")
}
if newStruct.StructVal.OtherData.OtherData.BadVal2 != "" {
t.Error("Value not wiped correctly")
}
vals, err = CheckJSON(sliceOfPrimitives, &exclusionList)
if err != nil {
t.Error("Check JSON error", err)
}
payload, err = json.Marshal(vals)
if err != nil {
t.Fatal("json marshal error", err)
}
var newSlice []any
err = json.Unmarshal(payload, &newSlice)
if err != nil {
t.Fatal("Unmarshal error", err)
}
assert.Len(t, newStruct, 4)
assert.Empty(t, newStruct[0].StructVal.BadVal, "Value not wiped correctly")
assert.Empty(t, newStruct[0].StructVal.BadVal2, "Value not wiped correctly")
assert.Empty(t, newStruct[0].StructVal.OtherData.BadVal, "BadVal should be removed")
assert.Empty(t, newStruct[0].StructVal.OtherData.BadVal2, "BadVal2 should be removed")
assert.Len(t, newStruct[0].MixedSlice[0], 4)
assert.Len(t, newStruct[0].MixedSlice[1], 7)
}
func TestGetExcludedItems(t *testing.T) {
exclusionList, err := GetExcludedItems()
if err != nil {
t.Error("GetExcludedItems error", err)
}
func TestHTTPRecord(t *testing.T) {
t.Parallel()
if len(exclusionList.Headers) == 0 {
t.Error("Header exclusion list not popoulated")
}
service := "mock"
outputDirPath := filepath.Join("..", service, "testdata")
err := os.Mkdir(outputDirPath, 0o755)
require.NoError(t, err)
if len(exclusionList.Variables) == 0 {
t.Error("Variable exclusion list not popoulated")
filePath := filepath.Join(outputDirPath, "http.json")
err = os.WriteFile(filePath, []byte(`{"routes": null}`), 0o644)
require.NoError(t, err)
_, err = os.Stat(filePath)
require.NoError(t, err, "file not created properly")
defer func() {
require.NoErrorf(t, os.Remove(filePath), "Remove test exclusion file %q must not error", filePath)
require.NoErrorf(t, os.Remove(outputDirPath), "Remove test exclusion dir %q must not error", outputDirPath)
}()
content, err := json.Marshal(testVal)
require.NoError(t, err, "Marshal must not error")
require.NotNil(t, content, "Marshal must not return nil")
response := &http.Response{
Request: &http.Request{
Method: http.MethodGet,
URL: &url.URL{},
},
}
err = HTTPRecord(response, "mock", content, 4)
require.NoError(t, err, "HTTPRecord must not error")
}

View File

@@ -29,6 +29,11 @@ const (
textPlain = "text/plain"
)
// error declarations
var (
errJSONMockFilePathRequired = errors.New("no path to json mock file found")
)
// VCRMock defines the main mock JSON file and attributes
type VCRMock struct {
Routes map[string]map[string][]HTTPResponse `json:"routes"`
@@ -38,7 +43,7 @@ type VCRMock struct {
// purposes and returns the server connection details
func NewVCRServer(path string) (string, *http.Client, error) {
if path == "" {
return "", nil, errors.New("no path to json mock file found")
return "", nil, errJSONMockFilePathRequired
}
var mockFile VCRMock
@@ -162,7 +167,7 @@ func RegisterHandler(pattern string, mock map[string][]HTTPResponse, mux *http.S
reqVals, err := DeriveURLValsFromJSONMap(readBody)
if err != nil {
log.Fatalf("Mock Test Failure - %v", err)
log.Fatalf("DeriveURLValsFromJSONMap Mock Test Failure - %v", err)
}
payload, err := MatchAndGetResponse(httpResponses, reqVals, false)

View File

@@ -2,11 +2,13 @@ package mock
import (
"bytes"
"net"
"net/http"
"os"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
)
@@ -24,9 +26,7 @@ const (
func TestNewVCRServer(t *testing.T) {
_, _, err := NewVCRServer("")
if err == nil {
t.Error("NewVCRServer error cannot be nil")
}
assert.ErrorIs(t, err, errJSONMockFilePathRequired)
// Set up mock data
test1 := VCRMock{}
@@ -38,41 +38,30 @@ func TestNewVCRServer(t *testing.T) {
Amount: 1,
Currency: "bitcoin",
})
if err != nil {
t.Fatal("marshal error", err)
}
require.NoError(t, err, "Marshal must not error")
testValue := HTTPResponse{Data: rp, QueryString: queryString, BodyParams: queryString}
test1.Routes["/test"][http.MethodGet] = []HTTPResponse{testValue}
payload, err := json.Marshal(test1)
if err != nil {
t.Fatal("marshal error", err)
}
require.NoError(t, err, "Marshal must not error")
err = os.WriteFile(testFile, payload, os.ModePerm)
if err != nil {
t.Fatal("marshal error", err)
}
require.NoError(t, err, "WriteFile must not error")
deets, client, err := NewVCRServer(testFile)
if err != nil {
t.Error("NewVCRServer error", err)
}
assert.NoError(t, err, "NewVCRServer should not error")
err = common.SetHTTPClient(client) // Set common package global HTTP Client
if err != nil {
t.Fatal(err)
}
require.NoError(t, err)
_, err = common.SendHTTPRequest(t.Context(),
http.MethodGet,
"http://localhost:300/somethingElse?"+queryString,
nil,
bytes.NewBufferString(""), true)
if err == nil {
t.Error("Sending http request expected an error")
}
var netErr *net.OpError
assert.ErrorAs(t, err, &netErr, "SendHTTPRequest should return a net.OpError for an invalid host")
// Expected good outcome
r, err := common.SendHTTPRequest(t.Context(),
@@ -80,47 +69,24 @@ func TestNewVCRServer(t *testing.T) {
deets,
nil,
bytes.NewBufferString(""), true)
if err != nil {
t.Error("Sending http request error", err)
}
if !strings.Contains(string(r), "404 page not found") {
t.Error("Was not expecting any value returned:", r)
}
assert.NoError(t, err, "SendHTTPRequest should not error")
assert.Contains(t, string(r), "404 page not found", "SendHTTPRequest return should only contain 404")
r, err = common.SendHTTPRequest(t.Context(),
http.MethodGet,
deets+"/test?"+queryString,
nil,
bytes.NewBufferString(""), true)
if err != nil {
t.Error("Sending http request error", err)
}
assert.NoError(t, err, "SendHTTPRequest should not error")
var res responsePayload
err = json.Unmarshal(r, &res)
if err != nil {
t.Error("unmarshal error", err)
}
if res.Price != 8000 {
t.Error("response error expected 8000 but received:",
res.Price)
}
if res.Amount != 1 {
t.Error("response error expected 1 but received:",
res.Amount)
}
if res.Currency != "bitcoin" {
t.Error("response error expected \"bitcoin\" but received:",
res.Currency)
}
assert.NoError(t, err, "Unmarshal should not error")
assert.Equalf(t, 8000.0, res.Price, "response error expected 8000 but received: %f", res.Price)
assert.Equalf(t, 1.0, res.Amount, "response error expected 1 but received: %f", res.Amount)
assert.Equalf(t, "bitcoin", res.Currency, "response error expected \"bitcoin\" but received: %s", res.Currency)
// clean up test.json file
err = os.Remove(testFile)
if err != nil {
t.Fatal("Remove error", err)
}
require.NoError(t, err, "Remove testFile must not error")
}