Repository: containous/traefik
Pull request #5549 (2019-09-30 01:04:57)

fix: return an error instead of panic.

### What does this PR do?

fix: return an error instead of panic.

### Motivation

Don't panic.

### More

- [x] Added/updated tests
- [ ] ~~Added/updated documentation~~



Patch:
diff --git a/pkg/config/file/raw_node.go b/pkg/config/file/raw_node.go
index 135e9cd68..8b5509ad5 100644
--- a/pkg/config/file/raw_node.go
+++ b/pkg/config/file/raw_node.go
@@ -1,6 +1,7 @@
 package file
 
 import (
+	"fmt"
 	"reflect"
 	"sort"
 	"strconv"
@@ -15,12 +16,15 @@ func decodeRawToNode(data map[string]interface{}, rootName string, filters ...st
 	}
 
 	vData := reflect.ValueOf(data)
-	decodeRaw(root, vData, filters...)
+	err := decodeRaw(root, vData, filters...)
+	if err != nil {
+		return nil, err
+	}
 
 	return root, nil
 }
 
-func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
+func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) error {
 	sortedKeys := sortKeys(vData, filters)
 
 	for _, key := range sortedKeys {
@@ -38,7 +42,11 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
 		case reflect.Bool:
 			fallthrough
 		case reflect.String:
-			child.Value = getSimpleValue(value)
+			value, err := getSimpleValue(value)
+			if err != nil {
+				return err
+			}
+			child.Value = value
 		case reflect.Slice:
 			var values []string
 
@@ -63,40 +71,52 @@ func decodeRaw(node *parser.Node, vData reflect.Value, filters ...string) {
 						}
 
 						child.Children = append(child.Children, ch)
-						decodeRaw(ch, sValue)
+						err := decodeRaw(ch, sValue)
+						if err != nil {
+							return err
+						}
 					} else {
-						values = append(values, getSimpleValue(sValue))
+						val, err := getSimpleValue(sValue)
+						if err != nil {
+							return err
+						}
+						values = append(values, val)
 					}
 				default:
-					panic("Unsupported slice type: " + item.Kind().String())
+					return fmt.Errorf("field %s uses unsupported slice type: %s", child.Name, item.Kind().String())
 				}
 			}
 
 			child.Value = strings.Join(values, ",")
 		case reflect.Map:
-			decodeRaw(child, value)
+			err := decodeRaw(child, value)
+			if err != nil {
+				return err
+			}
 		default:
-			panic("Unsupported type: " + value.Kind().String())
+			return fmt.Errorf("field %s uses unsupported type: %s", child.Name, value.Kind().String())
 		}
 
 		node.Children = append(node.Children, child)
 	}
+
+	return nil
 }
 
-func getSimpleValue(item reflect.Value) string {
+func getSimpleValue(item reflect.Value) (string, error) {
 	switch item.Kind() {
 	case reflect.String:
-		return item.String()
+		return item.String(), nil
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return strconv.FormatInt(item.Int(), 10)
+		return strconv.FormatInt(item.Int(), 10), nil
 	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		return strconv.FormatUint(item.Uint(), 10)
+		return strconv.FormatUint(item.Uint(), 10), nil
 	case reflect.Float32, reflect.Float64:
-		return strings.TrimSuffix(strconv.FormatFloat(item.Float(), 'f', 6, 64), ".000000")
+		return strings.TrimSuffix(strconv.FormatFloat(item.Float(), 'f', 6, 64), ".000000"), nil
 	case reflect.Bool:
-		return strconv.FormatBool(item.Bool())
+		return strconv.FormatBool(item.Bool()), nil
 	default:
-		panic("Unsupported Simple value type: " + item.Kind().String())
+		return "", fmt.Errorf("unsupported simple value type: %s", item.Kind().String())
 	}
 }
 


Test patch:
diff --git a/pkg/config/file/raw_node_test.go b/pkg/config/file/raw_node_test.go
index cd57c74bd..5b4ae64ae 100644
--- a/pkg/config/file/raw_node_test.go
+++ b/pkg/config/file/raw_node_test.go
@@ -538,3 +538,27 @@ func Test_decodeRawToNode(t *testing.T) {
 		})
 	}
 }
+
+func Test_decodeRawToNode_errors(t *testing.T) {
+	testCases := []struct {
+		desc string
+		data map[string]interface{}
+	}{
+		{
+			desc: "invalid type",
+			data: map[string]interface{}{
+				"foo": struct{}{},
+			},
+		},
+	}
+
+	for _, test := range testCases {
+		test := test
+		t.Run(test.desc, func(t *testing.T) {
+			t.Parallel()
+
+			_, err := decodeRawToNode(test.data, parser.DefaultRootName)
+			require.Error(t, err)
+		})
+	}
+}