mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-12 01:14:22 +00:00
This commit enhances the UnstructAdapter
* Added support for arbitrary data types rather than just strings * Added support for integer index-able arrays * Improve code coverage for kunstruct - kunstruct around 90% - helper at 100% * Update expansion.Expand method to preserve the original type of the variable * Ensure the int field such .spec.replicas can be used as a source in a first Deployment or as destination of a variable (in the second Deployment variable).
This commit is contained in:
committed by
Jerome Brette
parent
0dbe78149d
commit
ed03818e20
@@ -17,40 +17,139 @@ limitations under the License.
|
||||
package kunstruct
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetFieldValue(t *testing.T) {
|
||||
factory := NewKunstructuredFactoryImpl()
|
||||
kunstructured := factory.FromMap(map[string]interface{}{
|
||||
"Kind": "Service",
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"app": "application-name",
|
||||
},
|
||||
"name": "service-name",
|
||||
var kunstructured = NewKunstructuredFactoryImpl().FromMap(map[string]interface{}{
|
||||
"Kind": "Service",
|
||||
"metadata": map[string]interface{}{
|
||||
"labels": map[string]string{
|
||||
"app": "application-name",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"ports": map[string]interface{}{
|
||||
"port": "80",
|
||||
"name": "service-name",
|
||||
},
|
||||
"spec": map[string]interface{}{
|
||||
"ports": map[string]interface{}{
|
||||
"port": "80",
|
||||
},
|
||||
},
|
||||
"this": map[string]interface{}{
|
||||
"is": map[string]interface{}{
|
||||
"aNumber": int64(1000),
|
||||
"aFloat": float64(1.001),
|
||||
"aNilValue": nil,
|
||||
"aBool": true,
|
||||
"anEmptyMap": map[string]interface{}{},
|
||||
"anEmptySlice": []interface{}{},
|
||||
"unrecognizable": testing.InternalExample{
|
||||
Name: "fooBar",
|
||||
},
|
||||
},
|
||||
"this": map[string]interface{}{
|
||||
"is": map[string]interface{}{
|
||||
"aNumber": 1000,
|
||||
"aNilValue": nil,
|
||||
"anEmptyMap": map[string]interface{}{},
|
||||
"unrecognizable": testing.InternalExample{
|
||||
Name: "fooBar",
|
||||
},
|
||||
"that": []interface{}{
|
||||
"idx0",
|
||||
"idx1",
|
||||
"idx2",
|
||||
"idx3",
|
||||
},
|
||||
"those": []interface{}{
|
||||
map[string]interface{}{
|
||||
"field1": "idx0foo",
|
||||
"field2": "idx0bar",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": "idx1foo",
|
||||
"field2": "idx1bar",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": "idx2foo",
|
||||
"field2": "idx2bar",
|
||||
},
|
||||
},
|
||||
"these": []interface{}{
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{"idx010", "idx011"},
|
||||
"field2": []interface{}{"idx020", "idx021"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{"idx110", "idx111"},
|
||||
"field2": []interface{}{"idx120", "idx121"},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{"idx210", "idx211"},
|
||||
"field2": []interface{}{"idx220", "idx221"},
|
||||
},
|
||||
},
|
||||
"complextree": []interface{}{
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1010",
|
||||
"intsubfield": int64(1010),
|
||||
"floatsubfield": float64(1.010),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1011",
|
||||
"intsubfield": int64(1011),
|
||||
"floatsubfield": float64(1.011),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
"field2": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1020",
|
||||
"intsubfield": int64(1020),
|
||||
"floatsubfield": float64(1.020),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1021",
|
||||
"intsubfield": int64(1021),
|
||||
"floatsubfield": float64(1.021),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
map[string]interface{}{
|
||||
"field1": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1110",
|
||||
"intsubfield": int64(1110),
|
||||
"floatsubfield": float64(1.110),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1111",
|
||||
"intsubfield": int64(1111),
|
||||
"floatsubfield": float64(1.111),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
"field2": []interface{}{
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1120",
|
||||
"intsubfield": int64(1120),
|
||||
"floatsubfield": float64(1.1120),
|
||||
"boolfield": true,
|
||||
},
|
||||
map[string]interface{}{
|
||||
"stringsubfield": "idx1121",
|
||||
"intsubfield": int64(1121),
|
||||
"floatsubfield": float64(1.1121),
|
||||
"boolfield": false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
func TestGetFieldValue(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
expectedValue string
|
||||
expectedValue interface{}
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
@@ -96,17 +195,202 @@ func TestGetFieldValue(t *testing.T) {
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'this.is.aDeep.field.that.does.not.exist'",
|
||||
},
|
||||
{
|
||||
name: "emptyMap",
|
||||
pathToField: "this.is.anEmptyMap",
|
||||
errorExpected: false,
|
||||
expectedValue: map[string]interface{}{},
|
||||
},
|
||||
{
|
||||
name: "emptySlice",
|
||||
pathToField: "this.is.anEmptySlice",
|
||||
errorExpected: false,
|
||||
expectedValue: []interface{}{},
|
||||
},
|
||||
{
|
||||
name: "numberAsValue",
|
||||
pathToField: "this.is.aNumber",
|
||||
errorExpected: false,
|
||||
expectedValue: int64(1000),
|
||||
},
|
||||
{
|
||||
name: "floatAsValue",
|
||||
pathToField: "this.is.aFloat",
|
||||
errorExpected: false,
|
||||
expectedValue: float64(1.001),
|
||||
},
|
||||
{
|
||||
name: "boolAsValue",
|
||||
pathToField: "this.is.aBool",
|
||||
errorExpected: false,
|
||||
expectedValue: true,
|
||||
},
|
||||
{
|
||||
name: "nilAsValue",
|
||||
pathToField: "this.is.aNilValue",
|
||||
errorExpected: false,
|
||||
expectedValue: nil,
|
||||
},
|
||||
{
|
||||
name: "unrecognizable",
|
||||
pathToField: "this.is.unrecognizable.Name",
|
||||
errorExpected: true,
|
||||
errorMsg: ".this.is.unrecognizable.Name accessor error: {fooBar <nil> false} is of the type testing.InternalExample, expected map[string]interface{}",
|
||||
},
|
||||
{
|
||||
name: "validStringIndex",
|
||||
pathToField: "that[2]",
|
||||
expectedValue: "idx2",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "outOfBoundIndex",
|
||||
pathToField: "that[99]",
|
||||
errorMsg: "no field named 'that[99]'",
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "unknownSlice",
|
||||
pathToField: "unknown[0]",
|
||||
errorMsg: "no field named 'unknown[0]'",
|
||||
errorExpected: true,
|
||||
},
|
||||
{
|
||||
name: "sliceInSlice",
|
||||
pathToField: "that[2][0]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'that[2][0]'",
|
||||
},
|
||||
{
|
||||
name: "validStructIndex",
|
||||
pathToField: "those[1]",
|
||||
errorExpected: false,
|
||||
expectedValue: map[string]interface{}{"field1": "idx1foo", "field2": "idx1bar"},
|
||||
},
|
||||
{
|
||||
name: "validStructSubField",
|
||||
pathToField: "those[1].field2",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx1bar",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndex",
|
||||
pathToField: "these[1].field2[1]",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx121",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexSubfield",
|
||||
pathToField: "complextree[1].field2[1].stringsubfield",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx1121",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexInvalidName",
|
||||
pathToField: "complextree[1].field2[1].invalidsubfield",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'complextree[1].field2[1].invalidsubfield'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldNoneIntIndex",
|
||||
pathToField: "complextree[thisisnotanint]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'complextree[thisisnotanint]'",
|
||||
},
|
||||
{
|
||||
name: "invalidNoneIntIndex",
|
||||
pathToField: "complextree[thisisnotanint]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'complextree[thisisnotanint]'",
|
||||
},
|
||||
{
|
||||
name: "invalidIndexInIndex",
|
||||
pathToField: "complextree[1[0]]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'complextree[1[0]]'",
|
||||
},
|
||||
{
|
||||
name: "invalidClosingBrackets",
|
||||
pathToField: "complextree[1]]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'complextree[1]]'",
|
||||
},
|
||||
{
|
||||
name: "validFieldsWithQuotes",
|
||||
pathToField: "'complextree'[1].field2[1].'stringsubfield'",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx1121",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
s, err := kunstructured.GetFieldValue(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
expectedValue string
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "oneField",
|
||||
pathToField: "Kind",
|
||||
expectedValue: "Service",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "twoFields",
|
||||
pathToField: "metadata.name",
|
||||
expectedValue: "service-name",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "threeFields",
|
||||
pathToField: "spec.ports.port",
|
||||
expectedValue: "80",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "emptyMap",
|
||||
pathToField: "this.is.anEmptyMap",
|
||||
errorExpected: true,
|
||||
errorMsg: ".this.is.anEmptyMap accessor error: map[] is of the type map[string]interface {}, expected string",
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "emptySlice",
|
||||
pathToField: "this.is.anEmptySlice",
|
||||
errorExpected: true,
|
||||
errorMsg: ".this.is.anEmptySlice accessor error: [] is of the type []interface {}, expected string",
|
||||
},
|
||||
{
|
||||
name: "numberAsValue",
|
||||
pathToField: "this.is.aNumber",
|
||||
errorExpected: true,
|
||||
errorMsg: ".this.is.aNumber accessor error: 1000 is of the type int, expected string",
|
||||
errorMsg: ".this.is.aNumber accessor error: 1000 is of the type int64, expected string",
|
||||
},
|
||||
{
|
||||
name: "nilAsValue",
|
||||
@@ -115,34 +399,410 @@ func TestGetFieldValue(t *testing.T) {
|
||||
errorMsg: ".this.is.aNilValue accessor error: <nil> is of the type <nil>, expected string",
|
||||
},
|
||||
{
|
||||
name: "unrecognizable",
|
||||
pathToField: "this.is.unrecognizable.Name",
|
||||
name: "validStringIndex",
|
||||
pathToField: "that[2]",
|
||||
expectedValue: "idx2",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "validStructIndex",
|
||||
pathToField: "those[1]",
|
||||
errorExpected: true,
|
||||
errorMsg: ".this.is.unrecognizable.Name accessor error: {fooBar <nil> false} is of the type testing.InternalExample, expected map[string]interface{}",
|
||||
errorMsg: ".[1] accessor error: map[field1:idx1foo field2:idx1bar] is of the type map[string]interface {}, expected string",
|
||||
},
|
||||
{
|
||||
name: "validStructSubField",
|
||||
pathToField: "those[1].field2",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx1bar",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndex",
|
||||
pathToField: "these[1].field2[1]",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx121",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexSubfield",
|
||||
pathToField: "complextree[1].field2[1].stringsubfield",
|
||||
errorExpected: false,
|
||||
expectedValue: "idx1121",
|
||||
},
|
||||
{
|
||||
name: "invalidIndexInMap",
|
||||
pathToField: "this.is[1]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'this.is[1]'",
|
||||
},
|
||||
{
|
||||
name: "anotherInvalidIndexInMap",
|
||||
pathToField: "this.is[1].aString",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'this.is[1].aString'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
s, err := kunstructured.GetFieldValue(test.pathToField)
|
||||
s, err := kunstructured.GetString(test.pathToField)
|
||||
if test.errorExpected {
|
||||
if err == nil {
|
||||
t.Fatalf("%q; path %q - should return error, but no error returned",
|
||||
test.name, test.pathToField)
|
||||
}
|
||||
if test.errorMsg != err.Error() {
|
||||
t.Fatalf("%q; path %q - expected error: \"%s\", got error: \"%v\"",
|
||||
test.name, test.pathToField, test.errorMsg, err.Error())
|
||||
}
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("%q; path %q - unexpected error %v",
|
||||
test.name, test.pathToField, err)
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
if test.expectedValue != s {
|
||||
t.Fatalf("%q; Got: %s expected: %s",
|
||||
test.name, s, test.expectedValue)
|
||||
}
|
||||
|
||||
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetInt64(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
expectedValue int64
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "numberAsValue",
|
||||
pathToField: "this.is.aNumber",
|
||||
errorExpected: false,
|
||||
expectedValue: int64(1000),
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexSubfield",
|
||||
pathToField: "complextree[1].field2[1].intsubfield",
|
||||
errorExpected: false,
|
||||
expectedValue: int64(1121),
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
s, err := kunstructured.GetInt64(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetFloat64(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
expectedValue float64
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "floatAsValue",
|
||||
pathToField: "this.is.aFloat",
|
||||
errorExpected: false,
|
||||
expectedValue: float64(1.001),
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexSubfield",
|
||||
pathToField: "complextree[1].field2[1].floatsubfield",
|
||||
errorExpected: false,
|
||||
expectedValue: float64(1.1121),
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "index 99 is out of bounds",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
s, err := kunstructured.GetFloat64(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBool(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
expectedValue bool
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "boolAsValue",
|
||||
pathToField: "this.is.aBool",
|
||||
errorExpected: false,
|
||||
expectedValue: true,
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexSubfield",
|
||||
pathToField: "complextree[1].field2[1].boolfield",
|
||||
errorExpected: false,
|
||||
expectedValue: false,
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
s, err := kunstructured.GetBool(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
compareValues(t, test.name, test.pathToField, test.expectedValue, s)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStringMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "validStringMap",
|
||||
pathToField: "those[2]",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
_, err := kunstructured.GetStringMap(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "validMap",
|
||||
pathToField: "those[2]",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldIndexSubfield",
|
||||
pathToField: "complextree[1].field2[1]",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
_, err := kunstructured.GetMap(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStringSlice(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "validStringSlice",
|
||||
pathToField: "that",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
_, err := kunstructured.GetStringSlice(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSlice(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
pathToField string
|
||||
errorExpected bool
|
||||
errorMsg string
|
||||
}{
|
||||
{
|
||||
name: "validSlice1",
|
||||
pathToField: "that",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "validSlice2",
|
||||
pathToField: "those",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "validSlice3",
|
||||
pathToField: "these",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "validSlice4",
|
||||
pathToField: "complextree",
|
||||
errorExpected: false,
|
||||
},
|
||||
{
|
||||
name: "twoFieldsOneMissing",
|
||||
pathToField: "metadata.banana",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'metadata.banana'",
|
||||
},
|
||||
{
|
||||
name: "validStructSubFieldOutOfBoundIndex",
|
||||
pathToField: "these[1].field2[99]",
|
||||
errorExpected: true,
|
||||
errorMsg: "no field named 'these[1].field2[99]'",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
_, err := kunstructured.GetSlice(test.pathToField)
|
||||
if test.errorExpected {
|
||||
compareExpectedError(t, test.name, test.pathToField, err, test.errorMsg)
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
unExpectedError(t, test.name, test.pathToField, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unExpectedError function handles unexpected error
|
||||
func unExpectedError(t *testing.T, name string, pathToField string, err error) {
|
||||
t.Fatalf("%q; path %q - unexpected error %v", name, pathToField, err)
|
||||
}
|
||||
|
||||
// compareExpectedError compares the expectedError and the actualError return by GetFieldValue
|
||||
func compareExpectedError(t *testing.T, name string, pathToField string, err error, errorMsg string) {
|
||||
if err == nil {
|
||||
t.Fatalf("%q; path %q - should return error, but no error returned",
|
||||
name, pathToField)
|
||||
}
|
||||
|
||||
if errorMsg != err.Error() {
|
||||
t.Fatalf("%q; path %q - expected error: \"%s\", got error: \"%v\"",
|
||||
name, pathToField, errorMsg, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// compareValues compares the expectedValue and actualValue returned by GetFieldValue
|
||||
func compareValues(t *testing.T, name string, pathToField string, expectedValue interface{}, actualValue interface{}) {
|
||||
t.Helper()
|
||||
switch typedV := expectedValue.(type) {
|
||||
case nil, string, bool, float64, int, int64:
|
||||
if expectedValue != actualValue {
|
||||
t.Fatalf("%q; Got: %v Expected: %v", name, actualValue, expectedValue)
|
||||
}
|
||||
case map[string]interface{}:
|
||||
if !reflect.DeepEqual(expectedValue, actualValue) {
|
||||
t.Fatalf("%q; Got: %v Expected: %v", name, actualValue, expectedValue)
|
||||
}
|
||||
case []interface{}:
|
||||
if !reflect.DeepEqual(expectedValue, actualValue) {
|
||||
t.Fatalf("%q; Got: %v Expected: %v", name, actualValue, expectedValue)
|
||||
}
|
||||
default:
|
||||
t.Logf("%T value at `%s`", typedV, pathToField)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user