Skip to content

Commit

Permalink
feat: refactor jsonpath stuff a bit, use a new lib
Browse files Browse the repository at this point in the history
  • Loading branch information
Dave Sheldon committed Oct 9, 2023
1 parent 5a8e781 commit 318f25b
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 44 deletions.
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ require (
)

require (
github.com/PaesslerAG/gval v1.0.0 // indirect
github.com/AsaiYusuke/jsonpath v1.6.0 // indirect
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
Expand All @@ -26,7 +26,6 @@ require (
)

require (
github.com/PaesslerAG/jsonpath v0.1.1
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
Expand Down
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AsaiYusuke/jsonpath v1.6.0 h1:YagKI8icTdxHujVwsgmL4Cm3DYm36g+ymp9PTMXY67o=
github.com/AsaiYusuke/jsonpath v1.6.0/go.mod h1:XblL8QLThYDIvcQkFJJXDqfry/XAkMYEIOItWRZtz1s=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
Expand Down Expand Up @@ -240,6 +242,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/itchyny/gojq v0.12.13 h1:IxyYlHYIlspQHHTE0f3cJF0NKDMfajxViuhBLnHd/QU=
github.com/itchyny/gojq v0.12.13/go.mod h1:JzwzAqenfhrPUuwbmEz3nu3JQmFLlQTQMUcOdnu/Sf4=
github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
Expand Down Expand Up @@ -275,6 +281,8 @@ github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOA
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
Expand All @@ -295,6 +303,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/ohler55/ojg v1.19.4 h1:ZIgfyHI83aLx+fi1VoKn4I80HqWo45usWKnnxw94Mro=
github.com/ohler55/ojg v1.19.4/go.mod h1:uHcD1ErbErC27Zhb5Df2jUjbseLLcmOCo6oxSr3jZxo=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
Expand Down Expand Up @@ -568,6 +578,7 @@ golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
Expand Down
24 changes: 12 additions & 12 deletions napassert/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func NewAssert(query string, predicate string, expectation string) *Assert {
return assert
}

func Execute(assert *Assert, actual string) error {
func Execute(assert *Assert, actual interface{}) error {
query := assert.Query
predicate := assert.Predicate
expectation := assert.Expectation
Expand All @@ -75,7 +75,7 @@ func Execute(assert *Assert, actual string) error {
case "==":
result = actual == expectation
if result != desiredResult {
floatActual, err := strconv.ParseFloat(actual, 64)
floatActual, err := strconv.ParseFloat(fmt.Sprint(actual), 64)
if err != nil {
break
}
Expand All @@ -90,7 +90,7 @@ func Execute(assert *Assert, actual string) error {
case "!=":
result = actual != expectation
if result != desiredResult {
floatActual, err := strconv.ParseFloat(actual, 64)
floatActual, err := strconv.ParseFloat(fmt.Sprint(actual), 64)
if err != nil {
break
}
Expand All @@ -103,7 +103,7 @@ func Execute(assert *Assert, actual string) error {
result = floatActual != floatExpectation
}
case "<":
floatActual, err := strconv.ParseFloat(actual, 64)
floatActual, err := strconv.ParseFloat(fmt.Sprint(actual), 64)
if err != nil {
break
}
Expand All @@ -114,7 +114,7 @@ func Execute(assert *Assert, actual string) error {

result = floatActual < floatAssertValue
case "<=":
floatActual, err := strconv.ParseFloat(actual, 64)
floatActual, err := strconv.ParseFloat(fmt.Sprint(actual), 64)
if err != nil {
break
}
Expand All @@ -125,7 +125,7 @@ func Execute(assert *Assert, actual string) error {

result = floatActual <= floatAssertValue
case ">":
floatActual, err := strconv.ParseFloat(actual, 64)
floatActual, err := strconv.ParseFloat(fmt.Sprint(actual), 64)
if err != nil {
break
}
Expand All @@ -136,7 +136,7 @@ func Execute(assert *Assert, actual string) error {

result = floatActual > floatAssertValue
case ">=":
floatActual, err := strconv.ParseFloat(actual, 64)
floatActual, err := strconv.ParseFloat(fmt.Sprint(actual), 64)
if err != nil {
break
}
Expand All @@ -148,13 +148,13 @@ func Execute(assert *Assert, actual string) error {
result = floatActual >= floatAssertValue
case "matches":
re := regexp.MustCompile(expectation)
result = re.MatchString(actual)
result = re.MatchString(fmt.Sprint(actual))
case "contains":
result = strings.Contains(actual, expectation)
result = strings.Contains(fmt.Sprint(actual), expectation)
case "startswith":
result = strings.HasPrefix(actual, expectation)
result = strings.HasPrefix(fmt.Sprint(actual), expectation)
case "endswith":
result = strings.HasSuffix(actual, expectation)
result = strings.HasSuffix(fmt.Sprint(actual), expectation)
case "in":
validValues := []interface{}{}
data := []byte(expectation)
Expand All @@ -173,7 +173,7 @@ func Execute(assert *Assert, actual string) error {

// string didn't compare, let's parse to float and try again
floatVal, err := strconv.ParseFloat(strVal, 64)
floatActual, err2 := strconv.ParseFloat(actual, 64)
floatActual, err2 := strconv.ParseFloat(fmt.Sprint(actual), 64)

if err == nil && err2 == nil {
in = floatVal == floatActual
Expand Down
9 changes: 8 additions & 1 deletion napcap/cap.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ capture.go - this file contains logic for evaluating captures
package napcap

import (
"fmt"

"github.com/davesheldon/nap/napcontext"
"github.com/davesheldon/nap/napquery"
"github.com/davesheldon/nap/napscript"
Expand All @@ -34,6 +36,11 @@ func CaptureQuery(variable string, query string, ctx *napcontext.Context, vmData
return err
}

ctx.EnvironmentVariables[variable] = actual
if len(actual) > 0 {
ctx.EnvironmentVariables[variable] = fmt.Sprint(actual[0])
}

// todo: deal with multiple return values

return nil
}
14 changes: 7 additions & 7 deletions napcap/cap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,22 @@ func TestCaptures(t *testing.T) {
tests := map[string]struct {
variable string
ctx *napcontext.Context
queryFunc func(query string, vmData *napscript.VmHttpData) (string, error)
queryFunc func(query string, vmData *napscript.VmHttpData) ([]any, error)
}{
"set new variable": {
variable: "test1",
ctx: napcontext.New("", nil, make(map[string]string), nil, true),
queryFunc: mockQuery("value1", nil),
queryFunc: mockQuery([]any{"value1"}, nil),
},
"overwrite new variable": {
variable: "test1",
ctx: napcontext.New("", nil, map[string]string{"test1": "value1"}, nil, true),
queryFunc: mockQuery("value2", nil),
queryFunc: mockQuery([]any{"value2"}, nil),
},
"error": {
variable: "test1",
ctx: napcontext.New("", nil, make(map[string]string), nil, true),
queryFunc: mockQuery("", fmt.Errorf("mock error")),
queryFunc: mockQuery(nil, fmt.Errorf("mock error")),
},
}

Expand All @@ -38,7 +38,7 @@ func TestCaptures(t *testing.T) {
queryResult, queryError := test.queryFunc("", nil)
err := napcap.CaptureQuery(test.variable, "", test.ctx, nil)

if err == nil && queryError == nil && test.ctx.EnvironmentVariables[test.variable] != queryResult {
if err == nil && queryError == nil && test.ctx.EnvironmentVariables[test.variable] != queryResult[0] {
t.Errorf("Expected %s=%s, got %s", test.variable, queryResult, test.ctx.EnvironmentVariables[test.variable])
} else if queryError != nil && err == nil {
t.Errorf("Expected error, got nil")
Expand All @@ -49,8 +49,8 @@ func TestCaptures(t *testing.T) {
}
}

func mockQuery(mockResult string, mockError error) func(query string, vmData *napscript.VmHttpData) (string, error) {
q := func(query string, vmData *napscript.VmHttpData) (string, error) {
func mockQuery(mockResult []any, mockError error) func(query string, vmData *napscript.VmHttpData) ([]any, error) {
q := func(query string, vmData *napscript.VmHttpData) ([]any, error) {
return mockResult, mockError
}

Expand Down
43 changes: 30 additions & 13 deletions napquery/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,51 +22,68 @@ import (
"strconv"
"strings"

"github.com/PaesslerAG/jsonpath"

"github.com/AsaiYusuke/jsonpath"
"github.com/davesheldon/nap/napscript"
jsoniter "github.com/json-iterator/go"
)

var json = jsoniter.ConfigCompatibleWithStandardLibrary

func evalJsonPath(expression string, data interface{}) ([]interface{}, error) {
var config = jsonpath.Config{}
config.SetAggregateFunction(`length`, func(params []interface{}) (interface{}, error) {
if params == nil {
return nil, nil
}
return len(params), nil
})
return jsonpath.Retrieve(expression, data, config)
}

var (
EvalJsonPath = evalJsonPath
)

func Eval(query string, vmData *napscript.VmHttpData) (string, error) {
func Eval(query string, vmData *napscript.VmHttpData) ([]any, error) {
if vmData == nil || vmData.Response == nil {
// return empty here instead of erroring in case this assert is testing for absence of a value
return "", nil
return nil, nil
}

jsonExpression, isJsonPath := strings.CutPrefix(query, "jsonpath ")
if isJsonPath {
body := vmData.Response.JsonBody
value, err := jsonpath.Get(jsonExpression, body)
value, err := EvalJsonPath(jsonExpression, body)

if err != nil {
return "", err
return nil, err
}

return fmt.Sprint(value), nil
return value, nil
}

header, isHeader := strings.CutPrefix(query, "header ")
if isHeader {
if vmData.Response.Headers == nil {
return "", nil
return nil, nil
}

value := vmData.Response.Headers[header]

return strings.Join(value, ","), nil
return value, nil
}

if query == "status" {
return strconv.Itoa(vmData.Response.StatusCode), nil
return []any{strconv.Itoa(vmData.Response.StatusCode)}, nil
}

if query == "duration" {
return strconv.FormatInt(vmData.Response.ElapsedMs, 10), nil
return []any{strconv.FormatInt(vmData.Response.ElapsedMs, 10)}, nil
}

if query == "body" {
return vmData.Response.Body, nil
return []any{vmData.Response.Body}, nil
}

return "", fmt.Errorf("Query \"%s\" not recognized.", query)
return nil, fmt.Errorf("Query \"%s\" not recognized.", query)
}
8 changes: 7 additions & 1 deletion naprunner/requestrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,13 @@ func runRequest(ctx *napcontext.Context, runPath string, request *naprequest.Req
return result
}

err = napassert.Execute(v, actual)
var testVal interface{} = nil

if actual != nil && len(actual) > 0 {
testVal = actual[0]
}

err = napassert.Execute(v, testVal)

if err != nil {
result.Error = err
Expand Down
17 changes: 10 additions & 7 deletions napscript/script.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ type VmHttpRequest struct {
}

type VmHttpResponse struct {
StatusCode int `json:"statusCode"`
Status string `json:"status"`
Body string `json:"body"`
JsonBody interface{} `json:"jsonBody"`
Headers map[string][]string `json:"headers"`
StatusCode int `json:"statusCode"`
Status string `json:"status"`
Body string `json:"body"`
JsonBody interface{} `json:"jsonBody"`
Headers map[string][]interface{} `json:"headers"`
ElapsedMs int64
}

Expand Down Expand Up @@ -190,11 +190,14 @@ func MapVmHttpData(result *naprequest.RequestResult) (*VmHttpData, error) {
defer result.HttpResponse.Body.Close()

// TODO: support multiple header values per key
data.Response.Headers = map[string][]string{}
data.Response.Headers = map[string][]any{}

for k, v := range result.HttpResponse.Header {
if len(v) > 0 {
data.Response.Headers[k] = v
data.Response.Headers[k] = make([]any, len(v))
for i, val := range v {
data.Response.Headers[k][i] = val
}

if k == "Content-Type" && strings.Contains(v[0], "json") {
err = json.Unmarshal(bodyBytes, &data.Response.JsonBody)
Expand Down

0 comments on commit 318f25b

Please sign in to comment.