mirror of
https://gitee.com/johng/gf
synced 2026-06-07 02:12:11 +08:00
## Summary - Add `GetEffective` and `MustGetEffective` methods following 12-Factor App config priority - Priority: Command line > Environment variables > Config file > Default value - Add clarifying notes to existing `GetWithEnv`/`GetWithCmd` methods - Add comprehensive unit tests ## Test plan - [x] All gcfg unit tests pass (44 tests) - [x] New `Test_GetEffective` covers 6 scenarios: - Config file only - Env overrides config - Cmd overrides env - Default value fallback - Empty string override (industry standard) - Key only in env Closes #4650 --------- Co-authored-by: John Guo <claymore1986@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
275 lines
7.0 KiB
Go
275 lines
7.0 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
// If a copy of the MIT was not distributed with this file,
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
// go test *.go -bench=".*" -benchmem
|
|
|
|
package gcfg_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/gogf/gf/v2/os/gcfg"
|
|
"github.com/gogf/gf/v2/os/gcmd"
|
|
"github.com/gogf/gf/v2/os/genv"
|
|
"github.com/gogf/gf/v2/os/gfile"
|
|
"github.com/gogf/gf/v2/os/gtime"
|
|
"github.com/gogf/gf/v2/test/gtest"
|
|
)
|
|
|
|
func Test_Basic1(t *testing.T) {
|
|
config := `
|
|
v1 = 1
|
|
v2 = "true"
|
|
v3 = "off"
|
|
v4 = "1.23"
|
|
array = [1,2,3]
|
|
[redis]
|
|
disk = "127.0.0.1:6379,0"
|
|
cache = "127.0.0.1:6379,1"
|
|
`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
var (
|
|
path = gcfg.DefaultConfigFileName
|
|
err = gfile.PutContents(path, config)
|
|
)
|
|
t.AssertNil(err)
|
|
defer gfile.Remove(path)
|
|
|
|
c, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
t.Assert(c.MustGet(ctx, "v1"), 1)
|
|
filepath, _ := c.GetAdapter().(*gcfg.AdapterFile).GetFilePath()
|
|
t.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)
|
|
})
|
|
}
|
|
|
|
func Test_Basic2(t *testing.T) {
|
|
config := `log-path = "logs"`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
var (
|
|
path = gcfg.DefaultConfigFileName
|
|
err = gfile.PutContents(path, config)
|
|
)
|
|
t.AssertNil(err)
|
|
defer func() {
|
|
_ = gfile.Remove(path)
|
|
}()
|
|
|
|
c, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
t.Assert(c.MustGet(ctx, "log-path"), "logs")
|
|
})
|
|
}
|
|
|
|
func Test_Content(t *testing.T) {
|
|
content := `
|
|
v1 = 1
|
|
v2 = "true"
|
|
v3 = "off"
|
|
v4 = "1.23"
|
|
array = [1,2,3]
|
|
[redis]
|
|
disk = "127.0.0.1:6379,0"
|
|
cache = "127.0.0.1:6379,1"
|
|
`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
c, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
c.GetAdapter().(*gcfg.AdapterFile).SetContent(content)
|
|
defer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()
|
|
t.Assert(c.MustGet(ctx, "v1"), 1)
|
|
})
|
|
}
|
|
|
|
func Test_SetFileName(t *testing.T) {
|
|
config := `
|
|
{
|
|
"array": [
|
|
1,
|
|
2,
|
|
3
|
|
],
|
|
"redis": {
|
|
"cache": "127.0.0.1:6379,1",
|
|
"disk": "127.0.0.1:6379,0"
|
|
},
|
|
"v1": 1,
|
|
"v2": "true",
|
|
"v3": "off",
|
|
"v4": "1.234"
|
|
}
|
|
`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
path := "config.json"
|
|
err := gfile.PutContents(path, config)
|
|
t.AssertNil(err)
|
|
defer func() {
|
|
_ = gfile.Remove(path)
|
|
}()
|
|
|
|
config, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
c := config.GetAdapter().(*gcfg.AdapterFile)
|
|
c.SetFileName(path)
|
|
t.Assert(c.MustGet(ctx, "v1"), 1)
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Int(), 1)
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Int8(), int8(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Int16(), int16(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Int32(), int32(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Int64(), int64(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Uint(), uint(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Uint8(), uint8(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Uint16(), uint16(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Uint32(), uint32(1))
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Uint64(), uint64(1))
|
|
|
|
t.AssertEQ(c.MustGet(ctx, "v1").String(), "1")
|
|
t.AssertEQ(c.MustGet(ctx, "v1").Bool(), true)
|
|
t.AssertEQ(c.MustGet(ctx, "v2").String(), "true")
|
|
t.AssertEQ(c.MustGet(ctx, "v2").Bool(), true)
|
|
|
|
t.AssertEQ(c.MustGet(ctx, "v1").String(), "1")
|
|
t.AssertEQ(c.MustGet(ctx, "v4").Float32(), float32(1.234))
|
|
t.AssertEQ(c.MustGet(ctx, "v4").Float64(), float64(1.234))
|
|
t.AssertEQ(c.MustGet(ctx, "v2").String(), "true")
|
|
t.AssertEQ(c.MustGet(ctx, "v2").Bool(), true)
|
|
t.AssertEQ(c.MustGet(ctx, "v3").Bool(), false)
|
|
|
|
t.AssertEQ(c.MustGet(ctx, "array").Ints(), []int{1, 2, 3})
|
|
t.AssertEQ(c.MustGet(ctx, "array").Strings(), []string{"1", "2", "3"})
|
|
t.AssertEQ(c.MustGet(ctx, "array").Interfaces(), []any{1, 2, 3})
|
|
t.AssertEQ(c.MustGet(ctx, "redis").Map(), map[string]any{
|
|
"disk": "127.0.0.1:6379,0",
|
|
"cache": "127.0.0.1:6379,1",
|
|
})
|
|
filepath, _ := c.GetFilePath()
|
|
t.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)
|
|
})
|
|
}
|
|
|
|
func TestCfg_Get_WrongConfigFile(t *testing.T) {
|
|
gtest.C(t, func(t *gtest.T) {
|
|
var err error
|
|
configPath := gfile.Temp(gtime.TimestampNanoStr())
|
|
err = gfile.Mkdir(configPath)
|
|
t.AssertNil(err)
|
|
defer gfile.Remove(configPath)
|
|
|
|
defer gfile.Chdir(gfile.Pwd())
|
|
err = gfile.Chdir(configPath)
|
|
t.AssertNil(err)
|
|
|
|
err = gfile.PutContents(
|
|
gfile.Join(configPath, "config.yml"),
|
|
"wrong config",
|
|
)
|
|
t.AssertNil(err)
|
|
adapterFile, err := gcfg.NewAdapterFile("config.yml")
|
|
t.AssertNil(err)
|
|
|
|
c := gcfg.NewWithAdapter(adapterFile)
|
|
v, err := c.Get(ctx, "name")
|
|
t.AssertNE(err, nil)
|
|
t.Assert(v, nil)
|
|
adapterFile.Clear()
|
|
})
|
|
}
|
|
|
|
func Test_GetWithEnv(t *testing.T) {
|
|
content := `
|
|
v1 = 1
|
|
v2 = "true"
|
|
v3 = "off"
|
|
v4 = "1.23"
|
|
array = [1,2,3]
|
|
[redis]
|
|
disk = "127.0.0.1:6379,0"
|
|
cache = "127.0.0.1:6379,1"
|
|
`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
c, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
c.GetAdapter().(*gcfg.AdapterFile).SetContent(content)
|
|
defer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()
|
|
t.Assert(c.MustGet(ctx, "v1"), 1)
|
|
t.Assert(c.MustGetWithEnv(ctx, `redis.user`), nil)
|
|
t.Assert(genv.Set("REDIS_USER", `1`), nil)
|
|
defer genv.Remove(`REDIS_USER`)
|
|
t.Assert(c.MustGetWithEnv(ctx, `redis.user`), `1`)
|
|
})
|
|
}
|
|
|
|
func Test_GetWithCmd(t *testing.T) {
|
|
content := `
|
|
v1 = 1
|
|
v2 = "true"
|
|
v3 = "off"
|
|
v4 = "1.23"
|
|
array = [1,2,3]
|
|
[redis]
|
|
disk = "127.0.0.1:6379,0"
|
|
cache = "127.0.0.1:6379,1"
|
|
`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
|
|
c, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
c.GetAdapter().(*gcfg.AdapterFile).SetContent(content)
|
|
defer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()
|
|
t.Assert(c.MustGet(ctx, "v1"), 1)
|
|
t.Assert(c.MustGetWithCmd(ctx, `redis.user`), nil)
|
|
|
|
gcmd.Init([]string{"gf", "--redis.user=2"}...)
|
|
t.Assert(c.MustGetWithCmd(ctx, `redis.user`), `2`)
|
|
})
|
|
}
|
|
|
|
func Test_GetEffective(t *testing.T) {
|
|
content := `
|
|
v1 = 1
|
|
v2 = "true"
|
|
[server]
|
|
port = 8080
|
|
host = "localhost"
|
|
[redis]
|
|
disk = "127.0.0.1:6379,0"
|
|
cache = "127.0.0.1:6379,1"
|
|
`
|
|
gtest.C(t, func(t *gtest.T) {
|
|
c, err := gcfg.New()
|
|
t.AssertNil(err)
|
|
c.GetAdapter().(*gcfg.AdapterFile).SetContent(content)
|
|
defer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()
|
|
|
|
// Test 1: Get from config file when no cmd/env set
|
|
t.Assert(c.MustGetEffective(ctx, "server.port"), 8080)
|
|
t.Assert(c.MustGetEffective(ctx, "server.host"), "localhost")
|
|
|
|
// Test 2: Environment variable overrides config file
|
|
t.Assert(genv.Set("SERVER_PORT", "9090"), nil)
|
|
defer genv.Remove("SERVER_PORT")
|
|
t.Assert(c.MustGetEffective(ctx, "server.port"), "9090")
|
|
|
|
// Test 3: Command line overrides environment variable
|
|
gcmd.Init([]string{"gf", "--server.port=7070"}...)
|
|
t.Assert(c.MustGetEffective(ctx, "server.port"), "7070")
|
|
|
|
// Test 4: Default value when nothing is set
|
|
t.Assert(c.MustGetEffective(ctx, "server.timeout", 30), 30)
|
|
|
|
// Test 5: Empty string from command line should override
|
|
gcmd.Init([]string{"gf", "--server.name="}...)
|
|
t.Assert(genv.Set("SERVER_NAME", "from-env"), nil)
|
|
defer genv.Remove("SERVER_NAME")
|
|
t.Assert(c.MustGetEffective(ctx, "server.name"), "")
|
|
|
|
// Test 6: Key not in config, only in env
|
|
t.Assert(genv.Set("APP_DEBUG", "true"), nil)
|
|
defer genv.Remove("APP_DEBUG")
|
|
t.Assert(c.MustGetEffective(ctx, "app.debug"), "true")
|
|
})
|
|
}
|