Merge pull request #31714 from smarterclayton/sync

Automatic merge from submit-queue

Allow missing keys in jsonpath
This commit is contained in:
Kubernetes Submit Queue 2016-09-08 22:22:16 -07:00 committed by GitHub
commit 3651765077
2 changed files with 24 additions and 6 deletions

View File

@ -34,6 +34,8 @@ type JSONPath struct {
beginRange int
inRange int
endRange int
allowMissingKeys bool
}
func New(name string) *JSONPath {
@ -45,6 +47,13 @@ func New(name string) *JSONPath {
}
}
// AllowMissingKeys allows a caller to specify whether they want an error if a field or map key
// cannot be located, or simply an empty result. The receiver is returned for chaining.
func (j *JSONPath) AllowMissingKeys(allow bool) *JSONPath {
j.allowMissingKeys = allow
return j
}
// Parse parse the given template, return error
func (j *JSONPath) Parse(text string) (err error) {
j.parser, err = Parse(j.name, text)
@ -305,7 +314,7 @@ func (j *JSONPath) findFieldInValue(value *reflect.Value, node *FieldNode) (refl
return value.FieldByName(node.Value), nil
}
// evalField evaluates filed of struct or key of map.
// evalField evaluates field of struct or key of map.
func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.Value, error) {
results := []reflect.Value{}
// If there's no input, there's no output
@ -338,6 +347,9 @@ func (j *JSONPath) evalField(input []reflect.Value, node *FieldNode) ([]reflect.
}
}
if len(results) == 0 {
if j.allowMissingKeys {
return results, nil
}
return results, fmt.Errorf("%s is not found", node.Value)
}
return results, nil

View File

@ -33,9 +33,10 @@ type jsonpathTest struct {
expect string
}
func testJSONPath(tests []jsonpathTest, t *testing.T) {
func testJSONPath(tests []jsonpathTest, allowMissingKeys bool, t *testing.T) {
for _, test := range tests {
j := New(test.name)
j.AllowMissingKeys(allowMissingKeys)
err := j.Parse(test.template)
if err != nil {
t.Errorf("in %s, parse %s error %v", test.name, test.template, err)
@ -166,10 +167,15 @@ func TestStructInput(t *testing.T) {
{"recurarray", "{..Book[2]}", storeData,
"{Category: fiction, Author: Herman Melville, Title: Moby Dick, Price: 8.99}"},
}
testJSONPath(storeTests, t)
testJSONPath(storeTests, false, t)
missingKeyTests := []jsonpathTest{
{"nonexistent field", "{.hello}", storeData, ""},
}
testJSONPath(missingKeyTests, true, t)
failStoreTests := []jsonpathTest{
{"invalid identfier", "{hello}", storeData, "unrecognized identifier hello"},
{"invalid identifier", "{hello}", storeData, "unrecognized identifier hello"},
{"nonexistent field", "{.hello}", storeData, "hello is not found"},
{"invalid array", "{.Labels[0]}", storeData, "map[string]int is not array or slice"},
{"invalid filter operator", "{.Book[?(@.Price<>10)]}", storeData, "unrecognized filter operator <>"},
@ -196,7 +202,7 @@ func TestJSONInput(t *testing.T) {
{"exists filter", "{[?(@.z)].id}", pointsData, "i2 i5"},
{"bracket key", "{[0]['id']}", pointsData, "i1"},
}
testJSONPath(pointsTests, t)
testJSONPath(pointsTests, false, t)
}
// TestKubernetes tests some use cases from kubernetes
@ -255,7 +261,7 @@ func TestKubernetes(t *testing.T) {
"[127.0.0.1, map[cpu:4]] [127.0.0.2, map[cpu:8]] "},
{"user password", `{.users[?(@.name=="e2e")].user.password}`, &nodesData, "secret"},
}
testJSONPath(nodesTests, t)
testJSONPath(nodesTests, false, t)
randomPrintOrderTests := []jsonpathTest{
{"recursive name", "{..name}", nodesData, `127.0.0.1 127.0.0.2 myself e2e`},