You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-zero/core/conf/config_test.go

542 lines
10 KiB
Go

package conf
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/fs"
"github.com/zeromicro/go-zero/core/hash"
)
func TestLoadConfig_notExists(t *testing.T) {
assert.NotNil(t, Load("not_a_file", nil))
}
func TestLoadConfig_notRecogFile(t *testing.T) {
filename, err := fs.TempFilenameWithText("hello")
assert.Nil(t, err)
defer os.Remove(filename)
assert.NotNil(t, Load(filename, nil))
}
func TestConfigJson(t *testing.T) {
tests := []string{
".json",
".yaml",
".yml",
}
text := `{
"a": "foo",
"b": 1,
"c": "${FOO}",
"d": "abcd!@#$112"
}`
for _, test := range tests {
test := test
t.Run(test, func(t *testing.T) {
os.Setenv("FOO", "2")
defer os.Unsetenv("FOO")
tmpfile, err := createTempFile(test, text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b"`
C string `json:"c"`
D string `json:"d"`
}
MustLoad(tmpfile, &val)
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "${FOO}", val.C)
assert.Equal(t, "abcd!@#$112", val.D)
})
}
}
func TestLoadFromJsonBytesArray(t *testing.T) {
input := []byte(`{"users": [{"name": "foo"}, {"Name": "bar"}]}`)
var val struct {
Users []struct {
Name string
}
}
assert.NoError(t, LoadFromJsonBytes(input, &val))
var expect []string
for _, user := range val.Users {
expect = append(expect, user.Name)
}
assert.EqualValues(t, []string{"foo", "bar"}, expect)
}
func TestConfigToml(t *testing.T) {
text := `a = "foo"
b = 1
c = "${FOO}"
d = "abcd!@#$112"
`
os.Setenv("FOO", "2")
defer os.Unsetenv("FOO")
tmpfile, err := createTempFile(".toml", text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b"`
C string `json:"c"`
D string `json:"d"`
}
MustLoad(tmpfile, &val)
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "${FOO}", val.C)
assert.Equal(t, "abcd!@#$112", val.D)
}
func TestConfigOptional(t *testing.T) {
text := `a = "foo"
b = 1
c = "FOO"
d = "abcd"
`
tmpfile, err := createTempFile(".toml", text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b,optional"`
C string `json:"c,optional=B"`
D string `json:"d,optional=b"`
}
if assert.NoError(t, Load(tmpfile, &val)) {
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "FOO", val.C)
assert.Equal(t, "abcd", val.D)
}
}
func TestConfigJsonCanonical(t *testing.T) {
text := []byte(`{"a": "foo", "B": "bar"}`)
var val1 struct {
A string `json:"a"`
B string `json:"b"`
}
var val2 struct {
A string
B string
}
assert.NoError(t, LoadFromJsonBytes(text, &val1))
assert.Equal(t, "foo", val1.A)
assert.Equal(t, "bar", val1.B)
assert.NoError(t, LoadFromJsonBytes(text, &val2))
assert.Equal(t, "foo", val2.A)
assert.Equal(t, "bar", val2.B)
}
func TestConfigTomlCanonical(t *testing.T) {
text := []byte(`a = "foo"
B = "bar"`)
var val1 struct {
A string `json:"a"`
B string `json:"b"`
}
var val2 struct {
A string
B string
}
assert.NoError(t, LoadFromTomlBytes(text, &val1))
assert.Equal(t, "foo", val1.A)
assert.Equal(t, "bar", val1.B)
assert.NoError(t, LoadFromTomlBytes(text, &val2))
assert.Equal(t, "foo", val2.A)
assert.Equal(t, "bar", val2.B)
}
func TestConfigYamlCanonical(t *testing.T) {
text := []byte(`a: foo
B: bar`)
var val1 struct {
A string `json:"a"`
B string `json:"b"`
}
var val2 struct {
A string
B string
}
assert.NoError(t, LoadFromYamlBytes(text, &val1))
assert.Equal(t, "foo", val1.A)
assert.Equal(t, "bar", val1.B)
assert.NoError(t, LoadFromYamlBytes(text, &val2))
assert.Equal(t, "foo", val2.A)
assert.Equal(t, "bar", val2.B)
}
func TestConfigTomlEnv(t *testing.T) {
text := `a = "foo"
b = 1
c = "${FOO}"
d = "abcd!@#112"
`
os.Setenv("FOO", "2")
defer os.Unsetenv("FOO")
tmpfile, err := createTempFile(".toml", text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b"`
C string `json:"c"`
D string `json:"d"`
}
MustLoad(tmpfile, &val, UseEnv())
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "2", val.C)
assert.Equal(t, "abcd!@#112", val.D)
}
func TestConfigJsonEnv(t *testing.T) {
tests := []string{
".json",
".yaml",
".yml",
}
text := `{
"a": "foo",
"b": 1,
"c": "${FOO}",
"d": "abcd!@#$a12 3"
}`
for _, test := range tests {
test := test
t.Run(test, func(t *testing.T) {
os.Setenv("FOO", "2")
defer os.Unsetenv("FOO")
tmpfile, err := createTempFile(test, text)
assert.Nil(t, err)
defer os.Remove(tmpfile)
var val struct {
A string `json:"a"`
B int `json:"b"`
C string `json:"c"`
D string `json:"d"`
}
MustLoad(tmpfile, &val, UseEnv())
assert.Equal(t, "foo", val.A)
assert.Equal(t, 1, val.B)
assert.Equal(t, "2", val.C)
assert.Equal(t, "abcd!@# 3", val.D)
})
}
}
func TestToCamelCase(t *testing.T) {
tests := []struct {
input string
expect string
}{
{
input: "",
expect: "",
},
{
input: "A",
expect: "a",
},
{
input: "a",
expect: "a",
},
{
input: "hello_world",
expect: "hello_world",
},
{
input: "Hello_world",
expect: "hello_world",
},
{
input: "hello_World",
expect: "hello_world",
},
{
input: "helloWorld",
expect: "helloworld",
},
{
input: "HelloWorld",
expect: "helloworld",
},
{
input: "hello World",
expect: "hello world",
},
{
input: "Hello World",
expect: "hello world",
},
{
input: "Hello World",
expect: "hello world",
},
{
input: "Hello World foo_bar",
expect: "hello world foo_bar",
},
{
input: "Hello World foo_Bar",
expect: "hello world foo_bar",
},
{
input: "Hello World Foo_bar",
expect: "hello world foo_bar",
},
{
input: "Hello World Foo_Bar",
expect: "hello world foo_bar",
},
{
input: "Hello.World Foo_Bar",
expect: "hello.world foo_bar",
},
{
input: "你好 World Foo_Bar",
expect: "你好 world foo_bar",
},
}
for _, test := range tests {
test := test
t.Run(test.input, func(t *testing.T) {
assert.Equal(t, test.expect, toLowerCase(test.input))
})
}
}
func TestLoadFromJsonBytesError(t *testing.T) {
var val struct{}
assert.Error(t, LoadFromJsonBytes([]byte(`hello`), &val))
}
func TestLoadFromTomlBytesError(t *testing.T) {
var val struct{}
assert.Error(t, LoadFromTomlBytes([]byte(`hello`), &val))
}
func TestLoadFromYamlBytesError(t *testing.T) {
var val struct{}
assert.Error(t, LoadFromYamlBytes([]byte(`':hello`), &val))
}
func TestLoadFromYamlBytes(t *testing.T) {
input := []byte(`layer1:
layer2:
layer3: foo`)
var val struct {
Layer1 struct {
Layer2 struct {
Layer3 string
}
}
}
assert.NoError(t, LoadFromYamlBytes(input, &val))
assert.Equal(t, "foo", val.Layer1.Layer2.Layer3)
}
func TestLoadFromYamlBytesTerm(t *testing.T) {
input := []byte(`layer1:
layer2:
tls_conf: foo`)
var val struct {
Layer1 struct {
Layer2 struct {
Layer3 string `json:"tls_conf"`
}
}
}
assert.NoError(t, LoadFromYamlBytes(input, &val))
assert.Equal(t, "foo", val.Layer1.Layer2.Layer3)
}
func TestLoadFromYamlBytesLayers(t *testing.T) {
input := []byte(`layer1:
layer2:
layer3: foo`)
var val struct {
Value string `json:"Layer1.Layer2.Layer3"`
}
assert.NoError(t, LoadFromYamlBytes(input, &val))
assert.Equal(t, "foo", val.Value)
}
func TestLoadFromYamlItemOverlay(t *testing.T) {
type (
Redis struct {
Host string
Port int
}
RedisKey struct {
Redis
Key string
}
Server struct {
Redis RedisKey
}
TestConfig struct {
Server
Redis Redis
}
)
input := []byte(`Redis:
Host: localhost
Port: 6379
Key: test
`)
var c TestConfig
if assert.NoError(t, LoadFromYamlBytes(input, &c)) {
assert.Equal(t, "localhost", c.Redis.Host)
assert.Equal(t, 6379, c.Redis.Port)
assert.Equal(t, "test", c.Server.Redis.Key)
}
}
func TestLoadFromYamlItemOverlayWithMap(t *testing.T) {
type (
Redis struct {
Host string
Port int
}
RedisKey struct {
Redis
Key string
}
Server struct {
Redis RedisKey
}
TestConfig struct {
Server
Redis map[string]interface{}
}
)
input := []byte(`Redis:
Host: localhost
Port: 6379
Key: test
`)
var c TestConfig
if assert.NoError(t, LoadFromYamlBytes(input, &c)) {
assert.Equal(t, "localhost", c.Server.Redis.Host)
assert.Equal(t, 6379, c.Server.Redis.Port)
assert.Equal(t, "test", c.Server.Redis.Key)
}
}
func TestUnmarshalJsonBytesMap(t *testing.T) {
input := []byte(`{"foo":{"/mtproto.RPCTos": "bff.bff","bar":"baz"}}`)
var val struct {
Foo map[string]string
}
assert.NoError(t, LoadFromJsonBytes(input, &val))
assert.Equal(t, "bff.bff", val.Foo["/mtproto.RPCTos"])
assert.Equal(t, "baz", val.Foo["bar"])
}
func TestUnmarshalJsonBytesMapWithSliceElements(t *testing.T) {
input := []byte(`{"foo":{"/mtproto.RPCTos": ["bff.bff", "any"],"bar":["baz", "qux"]}}`)
var val struct {
Foo map[string][]string
}
assert.NoError(t, LoadFromJsonBytes(input, &val))
assert.EqualValues(t, []string{"bff.bff", "any"}, val.Foo["/mtproto.RPCTos"])
assert.EqualValues(t, []string{"baz", "qux"}, val.Foo["bar"])
}
func TestUnmarshalJsonBytesMapWithSliceOfStructs(t *testing.T) {
input := []byte(`{"foo":{
"/mtproto.RPCTos": [{"bar": "any"}],
"bar":[{"bar": "qux"}, {"bar": "ever"}]}}`)
var val struct {
Foo map[string][]struct {
Bar string
}
}
assert.NoError(t, LoadFromJsonBytes(input, &val))
assert.Equal(t, 1, len(val.Foo["/mtproto.RPCTos"]))
assert.Equal(t, "any", val.Foo["/mtproto.RPCTos"][0].Bar)
assert.Equal(t, 2, len(val.Foo["bar"]))
assert.Equal(t, "qux", val.Foo["bar"][0].Bar)
assert.Equal(t, "ever", val.Foo["bar"][1].Bar)
}
func TestUnmarshalJsonBytesWithAnonymousField(t *testing.T) {
type (
Int int
InnerConf struct {
Name string
}
Conf struct {
Int
InnerConf
}
)
var (
input = []byte(`{"Name": "hello", "int": 3}`)
c Conf
)
assert.NoError(t, LoadFromJsonBytes(input, &c))
assert.Equal(t, "hello", c.Name)
assert.Equal(t, Int(3), c.Int)
}
func createTempFile(ext, text string) (string, error) {
tmpfile, err := os.CreateTemp(os.TempDir(), hash.Md5Hex([]byte(text))+"*"+ext)
if err != nil {
return "", err
}
if err := os.WriteFile(tmpfile.Name(), []byte(text), os.ModeTemporary); err != nil {
return "", err
}
filename := tmpfile.Name()
if err = tmpfile.Close(); err != nil {
return "", err
}
return filename, nil
}