diff --git a/kyaml/yaml/rnode.go b/kyaml/yaml/rnode.go index 75fc700f39..e0678a7eb5 100644 --- a/kyaml/yaml/rnode.go +++ b/kyaml/yaml/rnode.go @@ -546,6 +546,32 @@ func (rn *RNode) GetBinaryDataMap() map[string]string { return result } +// GetValidatedDataMap retrieves the data map and returns an error if the data +// map contains entries which are not included in the expectedKeys set. +func (rn *RNode) GetValidatedDataMap(expectedKeys []string) (map[string]string, error) { + dataMap := rn.GetDataMap() + err := rn.validateDataMap(dataMap, expectedKeys) + return dataMap, err +} + +func (rn *RNode) validateDataMap(dataMap map[string]string, expectedKeys []string) error { + if dataMap == nil { + return fmt.Errorf("The datamap is unassigned") + } + for key := range dataMap { + found := false + for _, expected := range expectedKeys { + if expected == key { + found = true + } + } + if !found { + return fmt.Errorf("an unexpected key (%v) was found", key) + } + } + return nil +} + func (rn *RNode) SetDataMap(m map[string]string) { if rn == nil { log.Fatal("cannot set data map on nil Rnode") diff --git a/kyaml/yaml/rnode_test.go b/kyaml/yaml/rnode_test.go index 9421b7cd2a..12843a99e6 100644 --- a/kyaml/yaml/rnode_test.go +++ b/kyaml/yaml/rnode_test.go @@ -4,6 +4,7 @@ package yaml import ( + "fmt" "reflect" "strings" "testing" @@ -186,6 +187,105 @@ func TestRNodeGetDataMap(t *testing.T) { } } +func TestRNodeGetValidatedDataMap(t *testing.T) { + emptyMap := map[string]string{} + testCases := map[string]struct { + theMap map[string]interface{} + theAllowedKeys []string + expected map[string]string + expectedError error + }{ + "nilResultEmptyKeys": { + theMap: nil, + theAllowedKeys: []string{}, + expected: emptyMap, + expectedError: nil, + }, + "empty": { + theMap: map[string]interface{}{}, + theAllowedKeys: []string{}, + expected: emptyMap, + expectedError: nil, + }, + "expectedKeysMatch": { + theMap: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "winnie", + }, + "data": map[string]string{ + "wine": "cabernet", + "truck": "ford", + "rocket": "falcon9", + "planet": "mars", + "city": "brownsville", + }, + }, + theAllowedKeys: []string{ + "wine", + "truck", + "rocket", + "planet", + "city", + "plane", + "country", + }, + // order irrelevant, because assert.Equals is smart about maps. + expected: map[string]string{ + "city": "brownsville", + "wine": "cabernet", + "planet": "mars", + "rocket": "falcon9", + "truck": "ford", + }, + expectedError: nil, + }, + "unexpectedKeyInConfigMap": { + theMap: map[string]interface{}{ + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": map[string]interface{}{ + "name": "winnie", + }, + "data": map[string]string{ + "wine": "cabernet", + "truck": "ford", + "rocket": "falcon9", + }, + }, + theAllowedKeys: []string{ + "wine", + "truck", + }, + // order irrelevant, because assert.Equals is smart about maps. + expected: map[string]string{ + "wine": "cabernet", + "rocket": "falcon9", + "truck": "ford", + }, + expectedError: fmt.Errorf("an unexpected key (rocket) was found"), + }, + } + + for n := range testCases { + tc := testCases[n] + t.Run(n, func(t *testing.T) { + rn, err := FromMap(tc.theMap) + if !assert.NoError(t, err) { + t.FailNow() + } + m, err := rn.GetValidatedDataMap(tc.theAllowedKeys) + if !assert.Equal(t, tc.expected, m) { + t.FailNow() + } + if !assert.Equal(t, tc.expectedError, err) { + t.FailNow() + } + }) + } +} + func TestRNodeSetDataMap(t *testing.T) { testCases := map[string]struct { theMap map[string]interface{}