mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-01 23:16:51 +00:00
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:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user