You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
341 lines
7.4 KiB
341 lines
7.4 KiB
package file |
|
|
|
import ( |
|
"errors" |
|
"os" |
|
"path/filepath" |
|
"reflect" |
|
"sync" |
|
"testing" |
|
"time" |
|
|
|
"github.com/go-kratos/kratos/v2/config" |
|
) |
|
|
|
const ( |
|
_testJSON = ` |
|
{ |
|
"test":{ |
|
"settings":{ |
|
"int_key":1000, |
|
"float_key":1000.1, |
|
"duration_key":10000, |
|
"string_key":"string_value" |
|
}, |
|
"server":{ |
|
"addr":"127.0.0.1", |
|
"port":8000 |
|
} |
|
}, |
|
"foo":[ |
|
{ |
|
"name":"nihao", |
|
"age":18 |
|
}, |
|
{ |
|
"name":"nihao", |
|
"age":18 |
|
} |
|
] |
|
}` |
|
|
|
_testJSONUpdate = ` |
|
{ |
|
"test":{ |
|
"settings":{ |
|
"int_key":1000, |
|
"float_key":1000.1, |
|
"duration_key":10000, |
|
"string_key":"string_value" |
|
}, |
|
"server":{ |
|
"addr":"127.0.0.1", |
|
"port":8000 |
|
} |
|
}, |
|
"foo":[ |
|
{ |
|
"name":"nihao", |
|
"age":18 |
|
}, |
|
{ |
|
"name":"nihao", |
|
"age":18 |
|
} |
|
], |
|
"bar":{ |
|
"event":"update" |
|
} |
|
}` |
|
|
|
// _testYaml = ` |
|
//Foo: |
|
// bar : |
|
// - {name: nihao,age: 1} |
|
// - {name: nihao,age: 1} |
|
// |
|
// |
|
//` |
|
) |
|
|
|
//func TestScan(t *testing.T) { |
|
// |
|
//} |
|
|
|
func TestFile(t *testing.T) { |
|
var ( |
|
path = filepath.Join(t.TempDir(), "test_config") |
|
file = filepath.Join(path, "test.json") |
|
data = []byte(_testJSON) |
|
) |
|
defer os.Remove(path) |
|
if err := os.MkdirAll(path, 0o700); err != nil { |
|
t.Error(err) |
|
} |
|
if err := os.WriteFile(file, data, 0o666); err != nil { |
|
t.Error(err) |
|
} |
|
testSource(t, file, data) |
|
testSource(t, path, data) |
|
testWatchFile(t, file) |
|
testWatchDir(t, path, file) |
|
} |
|
|
|
func testWatchFile(t *testing.T, path string) { |
|
t.Log(path) |
|
|
|
s := NewSource(path) |
|
watch, err := s.Watch() |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
|
|
f, err := os.OpenFile(path, os.O_RDWR, 0) |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
defer f.Close() |
|
_, err = f.WriteString(_testJSONUpdate) |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
kvs, err := watch.Next() |
|
if err != nil { |
|
t.Errorf(`watch.Next() error(%v)`, err) |
|
} |
|
if !reflect.DeepEqual(string(kvs[0].Value), _testJSONUpdate) { |
|
t.Errorf(`string(kvs[0].Value(%v) is not equal to _testJSONUpdate(%v)`, kvs[0].Value, _testJSONUpdate) |
|
} |
|
|
|
newFilepath := filepath.Join(filepath.Dir(path), "test1.json") |
|
if err = os.Rename(path, newFilepath); err != nil { |
|
t.Error(err) |
|
} |
|
kvs, err = watch.Next() |
|
if err == nil { |
|
t.Errorf(`watch.Next() error(%v)`, err) |
|
} |
|
if kvs != nil { |
|
t.Errorf(`watch.Next() error(%v)`, err) |
|
} |
|
|
|
err = watch.Stop() |
|
if err != nil { |
|
t.Errorf(`watch.Stop() error(%v)`, err) |
|
} |
|
|
|
if err := os.Rename(newFilepath, path); err != nil { |
|
t.Error(err) |
|
} |
|
} |
|
|
|
func testWatchDir(t *testing.T, path, file string) { |
|
t.Log(path) |
|
t.Log(file) |
|
|
|
s := NewSource(path) |
|
watch, err := s.Watch() |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
|
|
f, err := os.OpenFile(file, os.O_RDWR, 0) |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
defer f.Close() |
|
_, err = f.WriteString(_testJSONUpdate) |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
|
|
kvs, err := watch.Next() |
|
if err != nil { |
|
t.Errorf(`watch.Next() error(%v)`, err) |
|
} |
|
if !reflect.DeepEqual(string(kvs[0].Value), _testJSONUpdate) { |
|
t.Errorf(`string(kvs[0].Value(%v) is not equal to _testJSONUpdate(%v)`, kvs[0].Value, _testJSONUpdate) |
|
} |
|
} |
|
|
|
func testSource(t *testing.T, path string, data []byte) { |
|
t.Log(path) |
|
|
|
s := NewSource(path) |
|
kvs, err := s.Load() |
|
if err != nil { |
|
t.Error(err) |
|
} |
|
if string(kvs[0].Value) != string(data) { |
|
t.Errorf("no expected: %s, but got: %s", kvs[0].Value, data) |
|
} |
|
} |
|
|
|
func TestConfig(t *testing.T) { |
|
path := filepath.Join(t.TempDir(), "test_config.json") |
|
defer os.Remove(path) |
|
if err := os.WriteFile(path, []byte(_testJSON), 0o666); err != nil { |
|
t.Error(err) |
|
} |
|
c := config.New(config.WithSource( |
|
NewSource(path), |
|
)) |
|
testScan(t, c) |
|
|
|
testConfig(t, c) |
|
} |
|
|
|
func testConfig(t *testing.T, c config.Config) { |
|
expected := map[string]interface{}{ |
|
"test.settings.int_key": int64(1000), |
|
"test.settings.float_key": float64(1000.1), |
|
"test.settings.string_key": "string_value", |
|
"test.settings.duration_key": time.Duration(10000), |
|
"test.server.addr": "127.0.0.1", |
|
"test.server.port": int64(8000), |
|
} |
|
if err := c.Load(); err != nil { |
|
t.Error(err) |
|
} |
|
for key, value := range expected { |
|
switch value.(type) { |
|
case int64: |
|
if v, err := c.Value(key).Int(); err != nil { |
|
t.Error(key, value, err) |
|
} else if v != value { |
|
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v) |
|
} |
|
case float64: |
|
if v, err := c.Value(key).Float(); err != nil { |
|
t.Error(key, value, err) |
|
} else if v != value { |
|
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v) |
|
} |
|
case string: |
|
if v, err := c.Value(key).String(); err != nil { |
|
t.Error(key, value, err) |
|
} else if v != value { |
|
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v) |
|
} |
|
case time.Duration: |
|
if v, err := c.Value(key).Duration(); err != nil { |
|
t.Error(key, value, err) |
|
} else if v != value { |
|
t.Errorf("no expect key: %s value: %v, but got: %v", key, value, v) |
|
} |
|
} |
|
} |
|
// scan |
|
var settings struct { |
|
IntKey int64 `json:"int_key"` |
|
FloatKey float64 `json:"float_key"` |
|
StringKey string `json:"string_key"` |
|
DurationKey time.Duration `json:"duration_key"` |
|
} |
|
if err := c.Value("test.settings").Scan(&settings); err != nil { |
|
t.Error(err) |
|
} |
|
if v := expected["test.settings.int_key"]; settings.IntKey != v { |
|
t.Errorf("no expect int_key value: %v, but got: %v", settings.IntKey, v) |
|
} |
|
if v := expected["test.settings.float_key"]; settings.FloatKey != v { |
|
t.Errorf("no expect float_key value: %v, but got: %v", settings.FloatKey, v) |
|
} |
|
if v := expected["test.settings.string_key"]; settings.StringKey != v { |
|
t.Errorf("no expect string_key value: %v, but got: %v", settings.StringKey, v) |
|
} |
|
if v := expected["test.settings.duration_key"]; settings.DurationKey != v { |
|
t.Errorf("no expect duration_key value: %v, but got: %v", settings.DurationKey, v) |
|
} |
|
|
|
// not found |
|
if _, err := c.Value("not_found_key").Bool(); errors.Is(err, config.ErrNotFound) { |
|
t.Logf("not_found_key not match: %v", err) |
|
} |
|
} |
|
|
|
func testScan(t *testing.T, c config.Config) { |
|
type TestJSON struct { |
|
Test struct { |
|
Settings struct { |
|
IntKey int `json:"int_key"` |
|
FloatKey float64 `json:"float_key"` |
|
DurationKey int `json:"duration_key"` |
|
StringKey string `json:"string_key"` |
|
} `json:"settings"` |
|
Server struct { |
|
Addr string `json:"addr"` |
|
Port int `json:"port"` |
|
} `json:"server"` |
|
} `json:"test"` |
|
Foo []struct { |
|
Name string `json:"name"` |
|
Age int `json:"age"` |
|
} `json:"foo"` |
|
} |
|
var conf TestJSON |
|
if err := c.Load(); err != nil { |
|
t.Error(err) |
|
} |
|
if err := c.Scan(&conf); err != nil { |
|
t.Error(err) |
|
} |
|
t.Log(conf) |
|
} |
|
|
|
func TestMergeDataRace(t *testing.T) { |
|
path := filepath.Join(t.TempDir(), "test_config.json") |
|
defer os.Remove(path) |
|
if err := os.WriteFile(path, []byte(_testJSON), 0o666); err != nil { |
|
t.Error(err) |
|
} |
|
c := config.New(config.WithSource( |
|
NewSource(path), |
|
)) |
|
const count = 80 |
|
wg := &sync.WaitGroup{} |
|
wg.Add(2) |
|
startCh := make(chan struct{}) |
|
go func() { |
|
defer wg.Done() |
|
<-startCh |
|
for i := 0; i < count; i++ { |
|
var conf struct{} |
|
if err := c.Scan(&conf); err != nil { |
|
t.Error(err) |
|
} |
|
} |
|
}() |
|
|
|
go func() { |
|
defer wg.Done() |
|
<-startCh |
|
for i := 0; i < count; i++ { |
|
if err := c.Load(); err != nil { |
|
t.Error(err) |
|
} |
|
} |
|
}() |
|
close(startCh) |
|
wg.Wait() |
|
}
|
|
|