diff --git a/pkg/config/kv/kv_node.go b/pkg/config/kv/kv_node.go index 3cb4f6c30..4b5a83594 100644 --- a/pkg/config/kv/kv_node.go +++ b/pkg/config/kv/kv_node.go @@ -20,13 +20,13 @@ func DecodeToNode(pairs []*store.KVPair, rootName string, filters ...string) (*p var node *parser.Node for i, pair := range sortedPairs { - split := strings.FieldsFunc(pair.Key, func(c rune) bool { return c == '/' }) - - if split[0] != rootName { - return nil, fmt.Errorf("invalid label root %s", split[0]) + if !strings.HasPrefix(pair.Key, rootName+"/") { + return nil, fmt.Errorf("invalid label root %s", rootName) } - var parts []string + split := strings.Split(pair.Key[len(rootName)+1:], "/") + + parts := []string{rootName} for _, fragment := range split { if exp.MatchString(fragment) { parts = append(parts, "["+fragment+"]") diff --git a/pkg/config/kv/kv_test.go b/pkg/config/kv/kv_test.go index 26f1a5e03..c94da1bce 100644 --- a/pkg/config/kv/kv_test.go +++ b/pkg/config/kv/kv_test.go @@ -8,42 +8,93 @@ import ( ) func TestDecode(t *testing.T) { - pairs := mapToPairs(map[string]string{ - "traefik/fielda": "bar", - "traefik/fieldb": "1", - "traefik/fieldc": "true", - "traefik/fieldd/0": "one", - "traefik/fieldd/1": "two", - "traefik/fielde": "", - "traefik/fieldf/Test1": "A", - "traefik/fieldf/Test2": "B", - "traefik/fieldg/0/name": "A", - "traefik/fieldg/1/name": "B", - }) - - element := &sample{} - - err := Decode(pairs, element, "traefik") - require.NoError(t, err) - - expected := &sample{ - FieldA: "bar", - FieldB: 1, - FieldC: true, - FieldD: []string{"one", "two"}, - FieldE: &struct { - Name string - }{}, - FieldF: map[string]string{ - "Test1": "A", - "Test2": "B", + testCases := []struct { + desc string + rootName string + pairs map[string]string + expected *sample + }{ + { + desc: "simple case", + rootName: "traefik", + pairs: map[string]string{ + "traefik/fielda": "bar", + "traefik/fieldb": "1", + "traefik/fieldc": "true", + "traefik/fieldd/0": "one", + "traefik/fieldd/1": "two", + "traefik/fielde": "", + "traefik/fieldf/Test1": "A", + "traefik/fieldf/Test2": "B", + "traefik/fieldg/0/name": "A", + "traefik/fieldg/1/name": "B", + }, + expected: &sample{ + FieldA: "bar", + FieldB: 1, + FieldC: true, + FieldD: []string{"one", "two"}, + FieldE: &struct { + Name string + }{}, + FieldF: map[string]string{ + "Test1": "A", + "Test2": "B", + }, + FieldG: []sub{ + {Name: "A"}, + {Name: "B"}, + }, + }, }, - FieldG: []sub{ - {Name: "A"}, - {Name: "B"}, + { + desc: "multi-level root name", + rootName: "foo/bar/traefik", + pairs: map[string]string{ + "foo/bar/traefik/fielda": "bar", + "foo/bar/traefik/fieldb": "2", + "foo/bar/traefik/fieldc": "true", + "foo/bar/traefik/fieldd/0": "one", + "foo/bar/traefik/fieldd/1": "two", + "foo/bar/traefik/fielde": "", + "foo/bar/traefik/fieldf/Test1": "A", + "foo/bar/traefik/fieldf/Test2": "B", + "foo/bar/traefik/fieldg/0/name": "A", + "foo/bar/traefik/fieldg/1/name": "B", + }, + expected: &sample{ + FieldA: "bar", + FieldB: 2, + FieldC: true, + FieldD: []string{"one", "two"}, + FieldE: &struct { + Name string + }{}, + FieldF: map[string]string{ + "Test1": "A", + "Test2": "B", + }, + FieldG: []sub{ + {Name: "A"}, + {Name: "B"}, + }, + }, }, } - assert.Equal(t, expected, element) + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + element := &sample{} + + err := Decode(mapToPairs(test.pairs), element, test.rootName) + require.NoError(t, err) + + assert.Equal(t, test.expected, element) + }) + } } type sample struct {