diff --git a/pkg/config/file/file_node.go b/pkg/config/file/file_node.go index a18a8e8c4..3570c64d4 100644 --- a/pkg/config/file/file_node.go +++ b/pkg/config/file/file_node.go @@ -13,8 +13,7 @@ import ( ) // decodeFileToNode decodes the configuration in filePath in a tree of untyped nodes. -// If filters is not empty, it skips any configuration element whose name is -// not among filters. +// If filters is not empty, it skips any configuration element whose name is not among filters. func decodeFileToNode(filePath string, filters ...string) (*parser.Node, error) { content, err := ioutil.ReadFile(filePath) if err != nil { @@ -40,7 +39,20 @@ func decodeFileToNode(filePath string, filters ...string) (*parser.Node, error) return nil, fmt.Errorf("unsupported file extension: %s", filePath) } - return decodeRawToNode(data, parser.DefaultRootName, filters...) + if len(data) == 0 { + return nil, fmt.Errorf("no configuration found in file: %s", filePath) + } + + node, err := decodeRawToNode(data, parser.DefaultRootName, filters...) + if err != nil { + return nil, err + } + + if len(node.Children) == 0 { + return nil, fmt.Errorf("no valid configuration found in file: %s", filePath) + } + + return node, nil } func getRootFieldNames(element interface{}) []string { diff --git a/pkg/config/file/file_node_test.go b/pkg/config/file/file_node_test.go index 4b5b4e975..e301047a1 100644 --- a/pkg/config/file/file_node_test.go +++ b/pkg/config/file/file_node_test.go @@ -5,6 +5,7 @@ import ( "github.com/containous/traefik/v2/pkg/config/parser" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func Test_getRootFieldNames(t *testing.T) { @@ -42,17 +43,43 @@ func Test_getRootFieldNames(t *testing.T) { } } +func Test_decodeFileToNode_errors(t *testing.T) { + testCases := []struct { + desc string + confFile string + }{ + { + desc: "non existing file", + confFile: "./fixtures/not_existing.toml", + }, + { + desc: "file without content", + confFile: "./fixtures/empty.toml", + }, + { + desc: "file without any valid configuration", + confFile: "./fixtures/no_conf.toml", + }, + } + + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + node, err := decodeFileToNode(test.confFile, + "Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "CertificatesResolvers") + + require.Error(t, err) + assert.Nil(t, node) + }) + } +} + func Test_decodeFileToNode_compare(t *testing.T) { nodeToml, err := decodeFileToNode("./fixtures/sample.toml", "Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "CertificatesResolvers") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) nodeYaml, err := decodeFileToNode("./fixtures/sample.yml") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) assert.Equal(t, nodeToml, nodeYaml) } @@ -60,9 +87,7 @@ func Test_decodeFileToNode_compare(t *testing.T) { func Test_decodeFileToNode_Toml(t *testing.T) { node, err := decodeFileToNode("./fixtures/sample.toml", "Global", "ServersTransport", "EntryPoints", "Providers", "API", "Metrics", "Ping", "Log", "AccessLog", "Tracing", "HostResolver", "CertificatesResolvers") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expected := &parser.Node{ Name: "traefik", @@ -294,9 +319,7 @@ func Test_decodeFileToNode_Toml(t *testing.T) { func Test_decodeFileToNode_Yaml(t *testing.T) { node, err := decodeFileToNode("./fixtures/sample.yml") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) expected := &parser.Node{ Name: "traefik", diff --git a/pkg/config/file/fixtures/empty.toml b/pkg/config/file/fixtures/empty.toml new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/config/file/fixtures/no_conf.toml b/pkg/config/file/fixtures/no_conf.toml new file mode 100644 index 000000000..fd45fbc06 --- /dev/null +++ b/pkg/config/file/fixtures/no_conf.toml @@ -0,0 +1,2 @@ +[foo] + bar = "test"