diff --git a/config/config_test.go b/config/config_test.go index 314335cb8..061465871 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -2,7 +2,6 @@ package config import ( "errors" - "reflect" "testing" "github.com/go-kratos/kratos/v2/log" @@ -164,134 +163,3 @@ func TestConfig(t *testing.T) { assert.Equal(t, endpoint1, testConf.Endpoints[0]) assert.Equal(t, 2, len(testConf.Endpoints)) } - -func TestDefaultResolver(t *testing.T) { - var ( - portString = "8080" - countInt = 10 - rateFloat = 0.9 - ) - - data := map[string]interface{}{ - "foo": map[string]interface{}{ - "bar": map[string]interface{}{ - "notexist": "${NOTEXIST:100}", - "port": "${PORT:8081}", - "count": "${COUNT:0}", - "enable": "${ENABLE:false}", - "rate": "${RATE}", - "empty": "${EMPTY:foobar}", - "url": "${URL:http://example.com}", - "array": []interface{}{ - "${PORT}", - map[string]interface{}{"foobar": "${NOTEXIST:8081}"}, - }, - "value1": "${test.value}", - "value2": "$PORT", - "value3": "$PORT:default", - }, - }, - "test": map[string]interface{}{ - "value": "foobar", - }, - "PORT": "8080", - "COUNT": "10", - "ENABLE": "true", - "RATE": "0.9", - "EMPTY": "", - } - - tests := []struct { - name string - path string - expect interface{} - }{ - { - name: "test not exist int env with default", - path: "foo.bar.notexist", - expect: 100, - }, - { - name: "test string with default", - path: "foo.bar.port", - expect: portString, - }, - { - name: "test int with default", - path: "foo.bar.count", - expect: countInt, - }, - { - name: "test bool with default", - path: "foo.bar.enable", - expect: true, - }, - { - name: "test float without default", - path: "foo.bar.rate", - expect: rateFloat, - }, - { - name: "test empty value with default", - path: "foo.bar.empty", - expect: "", - }, - { - name: "test url with default", - path: "foo.bar.url", - expect: "http://example.com", - }, - { - name: "test array", - path: "foo.bar.array", - expect: []interface{}{portString, map[string]interface{}{"foobar": "8081"}}, - }, - { - name: "test ${test.value}", - path: "foo.bar.value1", - expect: "foobar", - }, - } - - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - err := defaultResolver(data) - assert.NoError(t, err) - rd := reader{ - values: data, - } - if v, ok := rd.Value(test.path); ok { - var actual interface{} - switch test.expect.(type) { - case int: - if actual, err = v.Int(); err == nil { - assert.Equal(t, test.expect, int(actual.(int64)), "int value should be equal") - } - case string: - if actual, err = v.String(); err == nil { - assert.Equal(t, test.expect, actual, "string value should be equal") - } - case bool: - if actual, err = v.Bool(); err == nil { - assert.Equal(t, test.expect, actual, "bool value should be equal") - } - case float64: - if actual, err = v.Float(); err == nil { - assert.Equal(t, test.expect, actual, "float64 value should be equal") - } - default: - actual = v.Load() - if !reflect.DeepEqual(test.expect, actual) { - t.Logf("expect: %#v, actural: %#v", test.expect, actual) - t.Fail() - } - } - if err != nil { - t.Error(err) - } - } else { - t.Error("value path not found") - } - }) - } -} diff --git a/config/options.go b/config/options.go index c86dd755c..d1cbeced8 100644 --- a/config/options.go +++ b/config/options.go @@ -124,10 +124,7 @@ func defaultResolver(input map[string]interface{}) error { } func expand(s string, mapping func(string) string) string { - r, err := regexp.Compile(`\${(.*?)}`) - if err != nil { - return s - } + r := regexp.MustCompile(`\${(.*?)}`) re := r.FindAllStringSubmatch(s, -1) for _, i := range re { if len(i) == 2 { diff --git a/config/options_test.go b/config/options_test.go index c3769166b..dd6bc538e 100644 --- a/config/options_test.go +++ b/config/options_test.go @@ -1,6 +1,7 @@ package config import ( + "reflect" "testing" "github.com/stretchr/testify/assert" @@ -35,3 +36,150 @@ func TestDefaultDecoder(t *testing.T) { }, }, target) } + +func TestDefaultResolver(t *testing.T) { + var ( + portString = "8080" + countInt = 10 + rateFloat = 0.9 + ) + + data := map[string]interface{}{ + "foo": map[string]interface{}{ + "bar": map[string]interface{}{ + "notexist": "${NOTEXIST:100}", + "port": "${PORT:8081}", + "count": "${COUNT:0}", + "enable": "${ENABLE:false}", + "rate": "${RATE}", + "empty": "${EMPTY:foobar}", + "url": "${URL:http://example.com}", + "array": []interface{}{ + "${PORT}", + map[string]interface{}{"foobar": "${NOTEXIST:8081}"}, + }, + "value1": "${test.value}", + "value2": "$PORT", + "value3": "abc${PORT}foo${COUNT}bar", + "value4": "${foo${bar}}", + }, + }, + "test": map[string]interface{}{ + "value": "foobar", + }, + "PORT": "8080", + "COUNT": "10", + "ENABLE": "true", + "RATE": "0.9", + "EMPTY": "", + } + + tests := []struct { + name string + path string + expect interface{} + }{ + { + name: "test not exist int env with default", + path: "foo.bar.notexist", + expect: 100, + }, + { + name: "test string with default", + path: "foo.bar.port", + expect: portString, + }, + { + name: "test int with default", + path: "foo.bar.count", + expect: countInt, + }, + { + name: "test bool with default", + path: "foo.bar.enable", + expect: true, + }, + { + name: "test float without default", + path: "foo.bar.rate", + expect: rateFloat, + }, + { + name: "test empty value with default", + path: "foo.bar.empty", + expect: "", + }, + { + name: "test url with default", + path: "foo.bar.url", + expect: "http://example.com", + }, + { + name: "test array", + path: "foo.bar.array", + expect: []interface{}{portString, map[string]interface{}{"foobar": "8081"}}, + }, + { + name: "test ${test.value}", + path: "foo.bar.value1", + expect: "foobar", + }, + { + name: "test $PORT", + path: "foo.bar.value2", + expect: "$PORT", + }, + { + name: "test abc${PORT}foo${COUNT}bar", + path: "foo.bar.value3", + expect: "abc8080foo10bar", + }, + { + name: "test ${foo${bar}}", + path: "foo.bar.value4", + expect: "}", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := defaultResolver(data) + assert.NoError(t, err) + rd := reader{ + values: data, + } + if v, ok := rd.Value(test.path); ok { + var actual interface{} + switch test.expect.(type) { + case int: + if actual, err = v.Int(); err == nil { + assert.Equal(t, test.expect, int(actual.(int64)), "int value should be equal") + } + case string: + if actual, err = v.String(); err == nil { + assert.Equal(t, test.expect, actual, "string value should be equal") + } + case bool: + if actual, err = v.Bool(); err == nil { + assert.Equal(t, test.expect, actual, "bool value should be equal") + } + case float64: + if actual, err = v.Float(); err == nil { + assert.Equal(t, test.expect, actual, "float64 value should be equal") + } + default: + actual = v.Load() + if !reflect.DeepEqual(test.expect, actual) { + t.Logf("expect: %#v, actural: %#v", test.expect, actual) + t.Fail() + } + } + if err != nil { + t.Error(err) + } + } else { + t.Error("value path not found") + } + }) + } +}