From 25a6c53533e9248fa5ca95e9f516037c2f4beb87 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 15 Mar 2019 14:54:01 +0800 Subject: [PATCH] add unit test cases for gfsnotify --- g/encoding/gjson/gjson.go | 5 + g/frame/gins/gins.go | 14 --- g/frame/gins/gins_config_test.go | 68 ++++++++++- g/frame/gins/gins_database_test.go | 2 +- g/frame/gins/gins_redis_test.go | 2 +- g/net/ghttp/ghttp_server_session.go | 33 ++--- g/os/gcfg/gcfg.go | 24 ++-- g/os/gfsnotify/gfsnotify_z_unit_test.go | 155 ++++++++++++++++++++++++ 8 files changed, 253 insertions(+), 50 deletions(-) create mode 100644 g/os/gfsnotify/gfsnotify_z_unit_test.go diff --git a/g/encoding/gjson/gjson.go b/g/encoding/gjson/gjson.go index 95bd233ee..7cbfef3ce 100644 --- a/g/encoding/gjson/gjson.go +++ b/g/encoding/gjson/gjson.go @@ -542,6 +542,11 @@ func (j *Json) Get(pattern...string) interface{} { return nil } +// 判断锁给定pattern是否数据存在 +func (j *Json) Contains(pattern...string) bool { + return j.Get(pattern...) != nil +} + // 计算指定pattern的元素长度(pattern对应数据类型为map[string]interface{}/[]interface{}时有效) func (j *Json) Len(pattern string) int { p := j.getPointerByPattern(pattern) diff --git a/g/frame/gins/gins.go b/g/frame/gins/gins.go index 168565654..5bb8f08a3 100644 --- a/g/frame/gins/gins.go +++ b/g/frame/gins/gins.go @@ -98,32 +98,18 @@ func Config(file...string) *gcfg.Config { envPath := cmdenv.Get("gf.gcfg.path").String() selfPath := gfile.SelfDir() mainPath := gfile.MainPkgPath() - config := gcfg.New(pwdPath, configFile) - // 添加工作目录下的config目录 - if path := envPath + gfile.Separator + "config"; gfile.Exists(path) { - config.AddPath(path) - } // 自定义的环境变量/启动参数路径,优先级最高,覆盖默认的工作目录 if envPath != "" && gfile.Exists(envPath) { config.SetPath(envPath) - if path := envPath + gfile.Separator + "config"; gfile.Exists(path) { - config.AddPath(path) - } } // 二进制文件执行目录 if selfPath != "" && gfile.Exists(selfPath) { config.AddPath(selfPath) - if path := selfPath + gfile.Separator + "config"; gfile.Exists(path) { - config.AddPath(path) - } } // 开发环境源码main包目录 if mainPath != "" && gfile.Exists(mainPath) { config.AddPath(mainPath) - if path := mainPath + gfile.Separator + "config"; gfile.Exists(path) { - config.AddPath(path) - } } return config }).(*gcfg.Config) diff --git a/g/frame/gins/gins_config_test.go b/g/frame/gins/gins_config_test.go index 9a54f8bde..aa31b353f 100644 --- a/g/frame/gins/gins_config_test.go +++ b/g/frame/gins/gins_config_test.go @@ -13,6 +13,7 @@ import ( "github.com/gogf/gf/g/os/gtime" "github.com/gogf/gf/g/test/gtest" "testing" + "time" ) func Test_Config(t *testing.T) { @@ -61,6 +62,23 @@ test = "v=1" gtest.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1") gtest.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0") }) + // for gfsnotify callbacks to refresh cache of config file + time.Sleep(500*time.Millisecond) + + // relative path, config folder + gtest.Case(t, func() { + path := "config/config.toml" + err := gfile.PutContents(path, config) + gtest.Assert(err, nil) + defer gfile.Remove(path) + defer gins.Config().Reload() + gtest.Assert(gins.Config().Get("test"), "v=1") + gtest.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1") + gtest.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0") + }) + // for gfsnotify callbacks to refresh cache of config file + time.Sleep(500*time.Millisecond) + gtest.Case(t, func() { path := "test.toml" err := gfile.PutContents(path, config) @@ -71,6 +89,23 @@ test = "v=1" gtest.Assert(gins.Config("test.toml").Get("database.default.1.host"), "127.0.0.1") gtest.Assert(gins.Config("test.toml").Get("redis.disk"), "127.0.0.1:6379,0") }) + // for gfsnotify callbacks to refresh cache of config file + time.Sleep(500*time.Millisecond) + + gtest.Case(t, func() { + path := "config/test.toml" + err := gfile.PutContents(path, config) + gtest.Assert(err, nil) + defer gfile.Remove(path) + defer gins.Config().Reload() + gtest.Assert(gins.Config("test.toml").Get("test"), "v=1") + gtest.Assert(gins.Config("test.toml").Get("database.default.1.host"), "127.0.0.1") + gtest.Assert(gins.Config("test.toml").Get("redis.disk"), "127.0.0.1:6379,0") + }) + // for gfsnotify callbacks to refresh cache of config file + time.Sleep(500*time.Millisecond) + + // absolute path gtest.Case(t, func() { path := fmt.Sprintf(`%s/%d`, gfile.TempDir(), gtime.Nanosecond()) @@ -84,6 +119,22 @@ test = "v=1" gtest.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1") gtest.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0") }) + time.Sleep(500*time.Millisecond) + + gtest.Case(t, func() { + path := fmt.Sprintf(`%s/%d/config`, gfile.TempDir(), gtime.Nanosecond()) + file := fmt.Sprintf(`%s/%s`, path, "config.toml") + err := gfile.PutContents(file, config) + gtest.Assert(err, nil) + defer gfile.Remove(file) + defer gins.Config().Reload() + gtest.Assert(gins.Config().AddPath(path), nil) + gtest.Assert(gins.Config().Get("test"), "v=1") + gtest.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1") + gtest.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0") + }) + time.Sleep(500*time.Millisecond) + gtest.Case(t, func() { path := fmt.Sprintf(`%s/%d`, gfile.TempDir(), gtime.Nanosecond()) file := fmt.Sprintf(`%s/%s`, path, "test.toml") @@ -91,10 +142,25 @@ test = "v=1" gtest.Assert(err, nil) defer gfile.Remove(file) defer gins.Config("test.toml").Reload() + + gtest.Assert(gins.Config("test.toml").AddPath(path), nil) + gtest.Assert(gins.Config("test.toml").Get("test"), "v=1") + gtest.Assert(gins.Config("test.toml").Get("database.default.1.host"), "127.0.0.1") + gtest.Assert(gins.Config("test.toml").Get("redis.disk"), "127.0.0.1:6379,0") + }) + time.Sleep(500*time.Millisecond) + + gtest.Case(t, func() { + path := fmt.Sprintf(`%s/%d/config`, gfile.TempDir(), gtime.Nanosecond()) + file := fmt.Sprintf(`%s/%s`, path, "test.toml") + err := gfile.PutContents(file, config) + gtest.Assert(err, nil) + defer gfile.Remove(file) + defer gins.Config("test.toml").Reload() + gtest.Assert(gins.Config("test.toml").AddPath(path), nil) gtest.Assert(gins.Config("test.toml").Get("test"), "v=1") gtest.Assert(gins.Config("test.toml").Get("database.default.1.host"), "127.0.0.1") gtest.Assert(gins.Config("test.toml").Get("redis.disk"), "127.0.0.1:6379,0") }) } - diff --git a/g/frame/gins/gins_database_test.go b/g/frame/gins/gins_database_test.go index d6c2aa8db..f91bbb49e 100644 --- a/g/frame/gins/gins_database_test.go +++ b/g/frame/gins/gins_database_test.go @@ -56,7 +56,7 @@ test = "v=2" defer gins.Config().Reload() // for gfsnotify callbacks to refresh cache of config file - time.Sleep(time.Second) + time.Sleep(500*time.Millisecond) gtest.Case(t, func() { fmt.Println("gins Test_Database", gins.Config().Get("test")) diff --git a/g/frame/gins/gins_redis_test.go b/g/frame/gins/gins_redis_test.go index b164380ab..a6f961b4f 100644 --- a/g/frame/gins/gins_redis_test.go +++ b/g/frame/gins/gins_redis_test.go @@ -56,7 +56,7 @@ test = "v=3" defer gins.Config().Reload() // for gfsnotify callbacks to refresh cache of config file - time.Sleep(time.Second) + time.Sleep(500*time.Millisecond) gtest.Case(t, func() { fmt.Println("gins Test_Redis", gins.Config().Get("test")) diff --git a/g/net/ghttp/ghttp_server_session.go b/g/net/ghttp/ghttp_server_session.go index 429262c6f..75e3fd091 100644 --- a/g/net/ghttp/ghttp_server_session.go +++ b/g/net/ghttp/ghttp_server_session.go @@ -104,8 +104,8 @@ func (s *Session) Contains (key string) bool { return false } -// 获取SESSION -func (s *Session) Get (key string) interface{} { +// 获取SESSION变量 +func (s *Session) Get(key string) interface{} { if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" { s.init() return s.data.Get(key) @@ -141,112 +141,95 @@ func (s *Session) UpdateExpire() { } } -// Deprecated, use GetVar instead. func (s *Session) GetString(key string) string { return gconv.String(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetBool(key string) bool { return gconv.Bool(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetInt(key string) int { return gconv.Int(s.Get(key)) } -// Deprecated, use GetVar instead. + func (s *Session) GetInt8(key string) int8 { return gconv.Int8(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetInt16(key string) int16 { return gconv.Int16(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetInt32(key string) int32 { return gconv.Int32(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetInt64(key string) int64 { return gconv.Int64(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetUint(key string) uint { return gconv.Uint(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetUint8(key string) uint8 { return gconv.Uint8(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetUint16(key string) uint16 { return gconv.Uint16(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetUint32(key string) uint32 { return gconv.Uint32(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetUint64(key string) uint64 { return gconv.Uint64(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetFloat32(key string) float32 { return gconv.Float32(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetFloat64(key string) float64 { return gconv.Float64(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetBytes(key string) []byte { return gconv.Bytes(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetInts(key string) []int { return gconv.Ints(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetFloats(key string) []float64 { return gconv.Floats(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetStrings(key string) []string { return gconv.Strings(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetInterfaces(key string) []interface{} { return gconv.Interfaces(s.Get(key)) } -// Deprecated, use GetVar instead. func (s *Session) GetTime(key string, format...string) time.Time { return gconv.Time(s.Get(key), format...) } -// Deprecated, use GetVar instead. +func (s *Session) GetGTime(key string, format...string) *gtime.Time { + return gconv.GTime(s.Get(key), format...) +} + func (s *Session) GetTimeDuration(key string) time.Duration { return gconv.TimeDuration(s.Get(key)) } -// Deprecated, use GetVar instead. -// (已废弃, 请使用GetVar) 将变量转换为对象,注意 objPointer 参数必须为struct指针 +// 将变量转换为对象,注意 objPointer 参数必须为struct指针 func (s *Session) GetStruct(key string, objPointer interface{}, attrMapping...map[string]string) error { return gconv.Struct(s.Get(key), objPointer, attrMapping...) } diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index 5c2486cc0..81a5f8aeb 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -66,13 +66,7 @@ func (c *Config) filePath(file...string) (path string) { if len(file) > 0 { name = file[0] } - c.paths.RLockFunc(func(array []string) { - for _, v := range array { - if path, _ = gspath.Search(v, name); path != "" { - break - } - } - }) + path = c.GetFilePath(name) if path == "" { buffer := bytes.NewBuffer(nil) if c.paths.Len() > 0 { @@ -133,7 +127,8 @@ func (c *Config) AddPath(path string) error { return nil } -// 获取指定文件的绝对路径,默认获取默认的配置文件路径,当指定的配置文件不存在时,返回空字符串,并且不会报错。 +// 查找配置文件,获取指定配置文件的绝对路径,默认获取默认的配置文件路径; +// 当指定的配置文件不存在时,返回空字符串,并且不会报错。 func (c *Config) GetFilePath(file...string) (path string) { name := c.name.Val() if len(file) > 0 { @@ -141,9 +136,14 @@ func (c *Config) GetFilePath(file...string) (path string) { } c.paths.RLockFunc(func(array []string) { for _, v := range array { + // 查找当前目录 if path, _ = gspath.Search(v, name); path != "" { break } + // 查找当前目录下的config子目录 + if path, _ = gspath.Search(v, "config" + gfile.Separator + name); path != "" { + break + } } }) return @@ -191,6 +191,14 @@ func (c *Config) GetVar(pattern string, file...string) gvar.VarRead { return gvar.New(nil, true) } +// 判断指定的配置项是否存在 +func (c *Config) Contains(pattern string, file...string) bool { + if j := c.getJson(file...); j != nil { + return j.Contains(pattern) + } + return false +} + // 获得一个键值对关联数组/哈希表,方便操作,不需要自己做类型转换 // 注意,如果获取的值不存在,或者类型与json类型不匹配,那么将会返回nil func (c *Config) GetMap(pattern string, file...string) map[string]interface{} { diff --git a/g/os/gfsnotify/gfsnotify_z_unit_test.go b/g/os/gfsnotify/gfsnotify_z_unit_test.go new file mode 100644 index 000000000..4dbbab861 --- /dev/null +++ b/g/os/gfsnotify/gfsnotify_z_unit_test.go @@ -0,0 +1,155 @@ +// Copyright 2019 gf Author(https://github.com/gogf/gf). 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 gfsnotify_test + +import ( + "github.com/gogf/gf/g/container/gtype" + "github.com/gogf/gf/g/os/gfile" + "github.com/gogf/gf/g/os/gfsnotify" + "github.com/gogf/gf/g/os/gtime" + "github.com/gogf/gf/g/test/gtest" + "github.com/gogf/gf/g/util/gconv" + "testing" + "time" +) + +func TestWatcher_AddRemove(t *testing.T) { + gtest.Case(t, func() { + path1 := gconv.String(gtime.Nanosecond()) + path2 := gconv.String(gtime.Nanosecond()) + "2" + gfile.PutContents(path1, "1") + defer func() { + gfile.Remove(path1) + gfile.Remove(path2) + }() + v := gtype.NewInt(1) + callback, err := gfsnotify.Add(path1, func(event *gfsnotify.Event) { + if event.IsWrite() { + v.Set(2) + return + } + if event.IsRename() { + v.Set(3) + gfsnotify.Exit() + return + } + }) + gtest.Assert(err, nil) + gtest.AssertNE(callback, nil) + + gfile.PutContents(path1, "2") + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 2) + + gfile.Rename(path1, path2) + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 3) + }) + + gtest.Case(t, func() { + path1 := gconv.String(gtime.Nanosecond()) + gfile.PutContents(path1, "1") + defer func() { + gfile.Remove(path1) + }() + v := gtype.NewInt(1) + callback, err := gfsnotify.Add(path1, func(event *gfsnotify.Event) { + if event.IsWrite() { + v.Set(2) + return + } + if event.IsRemove() { + v.Set(4) + return + } + }) + gtest.Assert(err, nil) + gtest.AssertNE(callback, nil) + + gfile.PutContents(path1, "2") + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 2) + + gfile.Remove(path1) + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 4) + + gfile.PutContents(path1, "1") + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 4) + }) +} + +func TestWatcher_Callback(t *testing.T) { + gtest.Case(t, func() { + path1 := gconv.String(gtime.Nanosecond()) + gfile.PutContents(path1, "1") + defer func() { + gfile.Remove(path1) + }() + v := gtype.NewInt(1) + callback, err := gfsnotify.Add(path1, func(event *gfsnotify.Event) { + if event.IsWrite() { + v.Set(2) + return + } + }) + gtest.Assert(err, nil) + gtest.AssertNE(callback, nil) + + gfile.PutContents(path1, "2") + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 2) + + v.Set(3) + gfsnotify.RemoveCallback(callback.Id) + gfile.PutContents(path1, "3") + time.Sleep(100*time.Millisecond) + gtest.Assert(v.Val(), 3) + }) + // multiple callbacks + gtest.Case(t, func() { + path1 := gconv.String(gtime.Nanosecond()) + gfile.PutContents(path1, "1") + defer func() { + gfile.Remove(path1) + }() + v1 := gtype.NewInt(1) + v2 := gtype.NewInt(1) + callback1, err1 := gfsnotify.Add(path1, func(event *gfsnotify.Event) { + if event.IsWrite() { + v1.Set(2) + return + } + }) + callback2, err2 := gfsnotify.Add(path1, func(event *gfsnotify.Event) { + if event.IsWrite() { + v2.Set(2) + return + } + }) + gtest.Assert(err1, nil) + gtest.Assert(err2, nil) + gtest.AssertNE(callback1, nil) + gtest.AssertNE(callback2, nil) + + gfile.PutContents(path1, "2") + time.Sleep(100*time.Millisecond) + gtest.Assert(v1.Val(), 2) + gtest.Assert(v2.Val(), 2) + + v1.Set(3) + v2.Set(3) + gfsnotify.RemoveCallback(callback1.Id) + gfile.PutContents(path1, "3") + time.Sleep(100*time.Millisecond) + gtest.Assert(v1.Val(), 3) + gtest.Assert(v2.Val(), 2) + }) +}