From 233d7e4962f61e9e8b4a4695f0cdab688ffc4368 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Mon, 21 Jan 2019 16:58:52 -0500 Subject: [PATCH] Fix jsonpath slice step handling --- .../client-go/util/jsonpath/jsonpath.go | 14 +- .../client-go/util/jsonpath/jsonpath_test.go | 137 +++++++++++++++++- .../k8s.io/client-go/util/jsonpath/parser.go | 2 +- .../client-go/util/jsonpath/parser_test.go | 1 - 4 files changed, 145 insertions(+), 9 deletions(-) diff --git a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go index 80410607024..78c0b1491e3 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath.go @@ -273,12 +273,16 @@ func (j *JSONPath) evalArray(input []reflect.Value, node *ArrayNode) ([]reflect. return result, nil } - if !params[2].Known { - value = value.Slice(params[0].Value, params[1].Value) - } else { - value = value.Slice3(params[0].Value, params[1].Value, params[2].Value) + value = value.Slice(params[0].Value, params[1].Value) + + step := 1 + if params[2].Known { + if params[2].Value <= 0 { + return input, fmt.Errorf("step must be >= 0") + } + step = params[2].Value } - for i := 0; i < value.Len(); i++ { + for i := 0; i < value.Len(); i += step { result = append(result, value.Index(i)) } } diff --git a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go index fd7253f95fb..1513e5e7c11 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/jsonpath_test.go @@ -40,12 +40,15 @@ func testJSONPath(tests []jsonpathTest, allowMissingKeys bool, t *testing.T) { j.AllowMissingKeys(allowMissingKeys) err := j.Parse(test.template) if err != nil { - t.Errorf("in %s, parse %s error %v", test.name, test.template, err) + if !test.expectError { + t.Errorf("in %s, parse %s error %v", test.name, test.template, err) + } + continue } buf := new(bytes.Buffer) err = j.Execute(buf, test.input) if test.expectError { - if test.expectError && err == nil { + if err == nil { t.Errorf("in %s, expected execute error", test.name) } continue @@ -519,3 +522,133 @@ func TestNegativeIndex(t *testing.T) { t, ) } + +func TestStep(t *testing.T) { + var input = []byte( + `{ + "apiVersion": "v1", + "kind": "Pod", + "spec": { + "containers": [ + { + "image": "radial/busyboxplus:curl", + "name": "fake0" + }, + { + "image": "radial/busyboxplus:curl", + "name": "fake1" + }, + { + "image": "radial/busyboxplus:curl", + "name": "fake2" + }, + { + "image": "radial/busyboxplus:curl", + "name": "fake3" + }, + { + "image": "radial/busyboxplus:curl", + "name": "fake4" + }, + { + "image": "radial/busyboxplus:curl", + "name": "fake5" + }]}}`) + + var data interface{} + err := json.Unmarshal(input, &data) + if err != nil { + t.Fatal(err) + } + + testJSONPath( + []jsonpathTest{ + { + "test containers[0:], it equals containers[0:6:1]", + `{.spec.containers[0:].name}`, + data, + "fake0 fake1 fake2 fake3 fake4 fake5", + false, + }, + { + "test containers[0:6:], it equals containers[0:6:1]", + `{.spec.containers[0:6:].name}`, + data, + "fake0 fake1 fake2 fake3 fake4 fake5", + false, + }, + { + "test containers[0:6:1]", + `{.spec.containers[0:6:1].name}`, + data, + "fake0 fake1 fake2 fake3 fake4 fake5", + false, + }, + { + "test containers[0:6:0], it errors", + `{.spec.containers[0:6:0].name}`, + data, + "", + true, + }, + { + "test containers[0:6:-1], it errors", + `{.spec.containers[0:6:-1].name}`, + data, + "", + true, + }, + { + "test containers[1:4:2]", + `{.spec.containers[1:4:2].name}`, + data, + "fake1 fake3", + false, + }, + { + "test containers[1:4:3]", + `{.spec.containers[1:4:3].name}`, + data, + "fake1", + false, + }, + { + "test containers[1:4:4]", + `{.spec.containers[1:4:4].name}`, + data, + "fake1", + false, + }, + { + "test containers[0:6:2]", + `{.spec.containers[0:6:2].name}`, + data, + "fake0 fake2 fake4", + false, + }, + { + "test containers[0:6:3]", + `{.spec.containers[0:6:3].name}`, + data, + "fake0 fake3", + false, + }, + { + "test containers[0:6:5]", + `{.spec.containers[0:6:5].name}`, + data, + "fake0 fake5", + false, + }, + { + "test containers[0:6:6]", + `{.spec.containers[0:6:6].name}`, + data, + "fake0", + false, + }, + }, + false, + t, + ) +} diff --git a/staging/src/k8s.io/client-go/util/jsonpath/parser.go b/staging/src/k8s.io/client-go/util/jsonpath/parser.go index 93d58295ff9..1af8f269f7e 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/parser.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/parser.go @@ -46,7 +46,7 @@ type Parser struct { var ( ErrSyntax = errors.New("invalid syntax") dictKeyRex = regexp.MustCompile(`^'([^']*)'$`) - sliceOperatorRex = regexp.MustCompile(`^(-?[\d]*)(:-?[\d]*)?(:[\d]*)?$`) + sliceOperatorRex = regexp.MustCompile(`^(-?[\d]*)(:-?[\d]*)?(:-?[\d]*)?$`) ) // Parse parsed the given text and return a node Parser. diff --git a/staging/src/k8s.io/client-go/util/jsonpath/parser_test.go b/staging/src/k8s.io/client-go/util/jsonpath/parser_test.go index 473815f877d..2ec4677b935 100644 --- a/staging/src/k8s.io/client-go/util/jsonpath/parser_test.go +++ b/staging/src/k8s.io/client-go/util/jsonpath/parser_test.go @@ -140,7 +140,6 @@ func TestFailParser(t *testing.T) { {"unrecognized character", "{*}", "unrecognized character in action: U+002A '*'"}, {"invalid number", "{+12.3.0}", "cannot parse number +12.3.0"}, {"unterminated array", "{[1}", "unterminated array"}, - {"invalid index", "{[::-1]}", "invalid array index ::-1"}, {"unterminated filter", "{[?(.price]}", "unterminated filter"}, } for _, test := range failParserTests {