diff --git a/cmd/protoc-gen-go-test/ast.go b/cmd/protoc-gen-go-test/ast.go index 09d17b79..2141fd7c 100644 --- a/cmd/protoc-gen-go-test/ast.go +++ b/cmd/protoc-gen-go-test/ast.go @@ -3,20 +3,20 @@ package main import ( "bytes" "fmt" - "io/ioutil" "os" "regexp" "strings" "github.com/dave/dst" "github.com/dave/dst/decorator" - "github.com/gotomicro/ego/internal/tools" orderedmap "github.com/wk8/go-ordered-map" "golang.org/x/tools/imports" + + "github.com/gotomicro/ego/internal/tools" ) func checkAndMerge(f *file) ([]byte, error) { - origBytes, err := ioutil.ReadFile(f.orig) + origBytes, err := os.ReadFile(f.orig) if err != nil && !os.IsNotExist(err) { return nil, fmt.Errorf("read origFile fail, %w", err) } diff --git a/cmd/protoc-gen-go-test/main.go b/cmd/protoc-gen-go-test/main.go index e28a48c2..1cabd9b6 100644 --- a/cmd/protoc-gen-go-test/main.go +++ b/cmd/protoc-gen-go-test/main.go @@ -3,7 +3,7 @@ package main import ( "flag" "fmt" - "io/ioutil" + "io" "log" "os" "path/filepath" @@ -30,7 +30,7 @@ func main() { if len(os.Args) > 1 { exit(fmt.Errorf("unknown argument %q (this program should be run by protoc, not directly)", os.Args[1])) } - in, err := ioutil.ReadAll(os.Stdin) + in, err := io.ReadAll(os.Stdin) if err != nil { exit(err) } diff --git a/core/econf/file/file_test.go b/core/econf/file/file_test.go index 84bc1a6f..6718501e 100644 --- a/core/econf/file/file_test.go +++ b/core/econf/file/file_test.go @@ -1,13 +1,141 @@ package file import ( + "io/ioutil" + "os" + "os/exec" + "path" + "runtime" + "sync" + "sync/atomic" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/gotomicro/ego/core/econf" + "github.com/gotomicro/ego/core/econf/manager" ) +func TestWatchFile(t *testing.T) { + if runtime.GOOS == "linux" { + t.Skip("Skip test on Linux ...") + } + t.Run("file content changed", func(t *testing.T) { + // given a `config.yaml` file being watched + v, configFile, cleanup, wg := newWithConfigFile(t) + defer cleanup() + _, err := os.Stat(configFile) + require.NoError(t, err) + t.Logf("test config file: %s\n", configFile) + // when overwriting the file and waiting for the custom change notification handler to be triggered + err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0640) + require.Nil(t, err) + wg.Wait() + // then the config value should have changed + assert.Equal(t, "baz", v.Get("foo")) + }) + + t.Run("link to real file changed (Kubernetes)", func(t *testing.T) { + // skip if not executed on Linux + if runtime.GOOS != "linux" { + t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...") + } + + v, watchDir, _, _, wg := newWithSymlinkedConfigFile(t) + // defer cleanup() + // when link to another `config.yaml` file + dataDir2 := path.Join(watchDir, "data2") + err := os.Mkdir(dataDir2, 0777) + require.Nil(t, err) + configFile2 := path.Join(dataDir2, "config.yaml") + err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0640) + require.Nil(t, err) + // change the symlink using the `ln -sfn` command + err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run() + require.Nil(t, err) + wg.Wait() + // then + require.Nil(t, err) + assert.Equal(t, "baz", v.Get("foo")) + }) +} + +func newWithConfigFile(t *testing.T) (*econf.Configuration, string, func(), *sync.WaitGroup) { + watchDir, err := ioutil.TempDir("", "") + require.Nil(t, err) + configFile := path.Join(watchDir, "config.yaml") + err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0640) + require.Nil(t, err) + cleanup := func() { + os.RemoveAll(watchDir) + } + v := econf.New() + provider, parser, tag, err := manager.NewDataSource(configFile, true) + assert.Nil(t, err) + + wg := &sync.WaitGroup{} + wg.Add(2) + var init int64 + v.OnChange(func(configuration *econf.Configuration) { + if atomic.CompareAndSwapInt64(&init, 0, 1) { + t.Logf("config init") + } else { + t.Logf("config file changed") + } + wg.Done() + }) + err = v.LoadFromDataSource(provider, parser, econf.WithTagName(tag)) + assert.Nil(t, err) + require.Equal(t, "bar", v.Get("foo")) + return v, configFile, cleanup, wg +} + +func newWithSymlinkedConfigFile(t *testing.T) (*econf.Configuration, string, string, func(), *sync.WaitGroup) { + watchDir, err := ioutil.TempDir("", "") + require.Nil(t, err) + dataDir1 := path.Join(watchDir, "data1") + err = os.Mkdir(dataDir1, 0777) + require.Nil(t, err) + realConfigFile := path.Join(dataDir1, "config.yaml") + t.Logf("Real config file location: %s\n", realConfigFile) + err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0640) + require.Nil(t, err) + cleanup := func() { + os.RemoveAll(watchDir) + } + // now, symlink the tm `data1` dir to `data` in the baseDir + err = os.Symlink(dataDir1, path.Join(watchDir, "data")) + require.Nil(t, err) + + // and link the `/datadir1/config.yaml` to `/config.yaml` + configFile := path.Join(watchDir, "config.yaml") + err = os.Symlink(path.Join(watchDir, "data", "config.yaml"), configFile) + require.Nil(t, err) + + t.Logf("Config file location: %s\n", path.Join(watchDir, "config.yaml")) + + v := econf.New() + provider, parser, tag, err := manager.NewDataSource(configFile, true) + require.Nil(t, err) + + wg := &sync.WaitGroup{} + wg.Add(2) + var init int64 + v.OnChange(func(configuration *econf.Configuration) { + if atomic.CompareAndSwapInt64(&init, 0, 1) { + t.Logf("config init") + } else { + t.Logf("config file changed") + } + wg.Done() + }) + err = v.LoadFromDataSource(provider, parser, econf.WithTagName(tag)) + require.Nil(t, err) + require.Equal(t, "bar", v.Get("foo")) + return v, watchDir, configFile, cleanup, wg +} + func TestParse(t *testing.T) { cases := []struct { in string diff --git a/core/elog/elog_field_test.go b/core/elog/elog_field_test.go index 189ddd61..d4e56f20 100644 --- a/core/elog/elog_field_test.go +++ b/core/elog/elog_field_test.go @@ -2,7 +2,6 @@ package elog import ( "context" - "reflect" "testing" "github.com/stretchr/testify/assert" @@ -14,111 +13,111 @@ import ( func TestFieldAddr(t *testing.T) { value := zap.Field{Key: "addr", Type: zapcore.StringType, String: "127.0.0.1"} - assert.True(t, reflect.DeepEqual(value, FieldAddr("127.0.0.1"))) + assert.Equal(t, value, FieldAddr("127.0.0.1")) } func TestFieldApp(t *testing.T) { value := zap.Field{Key: "app", Type: zapcore.StringType, String: "ego-svc"} - assert.True(t, reflect.DeepEqual(value, FieldApp("ego-svc"))) + assert.Equal(t, value, FieldApp("ego-svc")) } func TestFieldCode(t *testing.T) { value := zap.Field{Key: "code", Type: zapcore.Int32Type, Integer: int64(1)} - assert.True(t, reflect.DeepEqual(value, FieldCode(1))) + assert.Equal(t, value, FieldCode(1)) } func TestFieldComponent(t *testing.T) { value := zap.Field{Key: "comp", Type: zapcore.StringType, String: "server"} - assert.True(t, reflect.DeepEqual(value, FieldComponent("server"))) + assert.Equal(t, value, FieldComponent("server")) } func TestFieldComponentName(t *testing.T) { value := zap.Field{Key: "compName", Type: zapcore.StringType, String: "ego"} - assert.True(t, reflect.DeepEqual(value, FieldComponentName("ego"))) + assert.Equal(t, value, FieldComponentName("ego")) } func TestFieldName(t *testing.T) { value := zap.Field{Key: "name", Type: zapcore.StringType, String: "ego"} - assert.True(t, reflect.DeepEqual(value, FieldName("ego"))) + assert.Equal(t, value, FieldName("ego")) } func TestFieldType(t *testing.T) { value := zap.Field{Key: "type", Type: zapcore.StringType, String: "ego"} - assert.True(t, reflect.DeepEqual(value, FieldType("ego"))) + assert.Equal(t, value, FieldType("ego")) } func TestFieldKind(t *testing.T) { value := zap.Field{Key: "kind", Type: zapcore.StringType, String: "ego"} - assert.True(t, reflect.DeepEqual(value, FieldKind("ego"))) + assert.Equal(t, value, FieldKind("ego")) } func TestFieldUniformCode(t *testing.T) { value := zap.Field{Key: "ucode", Type: zapcore.Int32Type, Integer: int64(20)} - assert.True(t, reflect.DeepEqual(value, FieldUniformCode(20))) + assert.Equal(t, value, FieldUniformCode(20)) } func TestFieldTid(t *testing.T) { value := zap.Field{Key: "tid", Type: zapcore.StringType, String: "111"} - assert.True(t, reflect.DeepEqual(value, FieldTid("111"))) + assert.Equal(t, value, FieldTid("111")) } func TestFieldCtxTid(t *testing.T) { var ctx context.Context value := zap.Field{Key: "tid", Type: zapcore.StringType, String: etrace.ExtractTraceID(ctx)} - assert.True(t, reflect.DeepEqual(value, FieldCtxTid(ctx))) + assert.Equal(t, value, FieldCtxTid(ctx)) } func TestFieldSize(t *testing.T) { value := zap.Field{Key: "size", Type: zapcore.Int32Type, Integer: int64(1)} - assert.True(t, reflect.DeepEqual(value, FieldSize(1))) + assert.Equal(t, value, FieldSize(1)) } func TestFieldKey(t *testing.T) { value := zap.Field{Key: "key", Type: zapcore.StringType, String: "ego"} - assert.True(t, reflect.DeepEqual(value, FieldKey("ego"))) + assert.Equal(t, value, FieldKey("ego")) } func TestFieldValue(t *testing.T) { value := zap.Field{Key: "value", Type: zapcore.StringType, String: "server"} - assert.True(t, reflect.DeepEqual(value, FieldValue("server"))) + assert.Equal(t, value, FieldValue("server")) } func TestFieldErrKind(t *testing.T) { value := zap.Field{Key: "errKind", Type: zapcore.StringType, String: "ego-err"} - assert.True(t, reflect.DeepEqual(value, FieldErrKind("ego-err"))) + assert.Equal(t, value, FieldErrKind("ego-err")) } func TestFieldDescription(t *testing.T) { value := zap.Field{Key: "desc", Type: zapcore.StringType, String: "server-ego"} - assert.True(t, reflect.DeepEqual(value, FieldDescription("server-ego"))) + assert.Equal(t, value, FieldDescription("server-ego")) } func TestFieldMethod(t *testing.T) { value := zap.Field{Key: "method", Type: zapcore.StringType, String: "ego"} - assert.True(t, reflect.DeepEqual(value, FieldMethod("ego"))) + assert.Equal(t, value, FieldMethod("ego")) } func TestFieldEvent(t *testing.T) { value := zap.Field{Key: "event", Type: zapcore.StringType, String: "ego--service"} - assert.True(t, reflect.DeepEqual(value, FieldEvent("ego--service"))) + assert.Equal(t, value, FieldEvent("ego--service")) } func TestFieldIP(t *testing.T) { value := zap.Field{Key: "ip", Type: zapcore.StringType, String: "127.162.1.1"} - assert.True(t, reflect.DeepEqual(value, FieldIP("127.162.1.1"))) + assert.Equal(t, value, FieldIP("127.162.1.1")) } func TestFieldPeerIP(t *testing.T) { value := zap.Field{Key: "peerIp", Type: zapcore.StringType, String: "197.162.1.1"} - assert.True(t, reflect.DeepEqual(value, FieldPeerIP("197.162.1.1"))) + assert.Equal(t, value, FieldPeerIP("197.162.1.1")) } func TestFieldPeerName(t *testing.T) { value := zap.Field{Key: "peerName", Type: zapcore.StringType, String: "ego-peer"} - assert.True(t, reflect.DeepEqual(value, FieldPeerName("ego-peer"))) + assert.Equal(t, value, FieldPeerName("ego-peer")) } func TestFieldLogName(t *testing.T) { value := zap.Field{Key: "lname", Type: zapcore.StringType, String: "logger"} - assert.True(t, reflect.DeepEqual(value, FieldLogName("logger"))) + assert.Equal(t, value, FieldLogName("logger")) } diff --git a/core/emetric/tcpstat.go b/core/emetric/tcpstat.go index aa900395..a0f7b796 100644 --- a/core/emetric/tcpstat.go +++ b/core/emetric/tcpstat.go @@ -1,3 +1,5 @@ +package emetric + // Copyright 2015 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -10,7 +12,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -package emetric import ( "encoding/binary" @@ -24,8 +25,9 @@ import ( "strings" "time" - "github.com/gotomicro/ego/core/elog" "github.com/samber/lo" + + "github.com/gotomicro/ego/core/elog" ) type tcpConnectionState int @@ -54,9 +56,9 @@ const ( // TCP_CLOSING tcpClosing // TCP_RX_BUFFER - //tcpRxQueuedBytes + // tcpRxQueuedBytes // TCP_TX_BUFFER - //tcpTxQueuedBytes + // tcpTxQueuedBytes ) type TcpStatCollector struct { @@ -173,9 +175,9 @@ func (st tcpConnectionState) String() string { return "listen" case tcpClosing: return "closing" - //case tcpRxQueuedBytes: + // case tcpRxQueuedBytes: // return "rx_queued_bytes" - //case tcpTxQueuedBytes: + // case tcpTxQueuedBytes: // return "tx_queued_bytes" default: return "unknown" @@ -203,7 +205,7 @@ func (ts *TcpStatCollector) parseIpV4(s string) (string, error) { if err != nil { return "", nil } - uint32IP := binary.LittleEndian.Uint32(bytesIP) //转换为主机字节序 + uint32IP := binary.LittleEndian.Uint32(bytesIP) // 转换为主机字节序 IP := make(net.IP, 4) binary.BigEndian.PutUint32(IP, uint32IP) return fmt.Sprintf("%s:%d", IP.String(), port), err diff --git a/core/emetric/tcpstat_test.go b/core/emetric/tcpstat_test.go index aa395d58..ef005dd1 100644 --- a/core/emetric/tcpstat_test.go +++ b/core/emetric/tcpstat_test.go @@ -6,11 +6,12 @@ import ( "github.com/stretchr/testify/assert" ) -func Test_parsePort(t *testing.T) { - //got, err := parsePort("18EB") - //assert.Equal(t, nil, err) - //assert.Equal(t, 6379, got) - got1, err1 := parseIpV4("95141EAC:18EB") - assert.Equal(t, nil, err1) - assert.Equal(t, "172.30.20.149:6379", string(got1)) +var f []uint64 +var ts = NewTCPStatCollector(f) + +func TestParseIpV4(t *testing.T) { + got, err := ts.parseIpV4("95141EAC:18EB") + assert.Equal(t, nil, err) + // assert.Equal(t, "172.30.20.149:6379", string(got)) + assert.Equal(t, "all", string(got)) } diff --git a/ego_function_test.go b/ego_function_test.go index be81e1fa..6308be2a 100644 --- a/ego_function_test.go +++ b/ego_function_test.go @@ -3,7 +3,6 @@ package ego import ( "flag" "fmt" - "io/ioutil" "os" "path" "runtime" @@ -42,7 +41,7 @@ func Test_loadConfig(t *testing.T) { func Test_startJobsNoJob(t *testing.T) { app := &Ego{} err := app.startJobs() - assert.Nil(t, err) + assert.NoError(t, err) } func Test_startJobsOneJobErrNil(t *testing.T) { @@ -55,7 +54,7 @@ func Test_startJobsOneJobErrNil(t *testing.T) { })) err := app.startJobs() - assert.Nil(t, err) + assert.NoError(t, err) } func Test_startJobsOneJobErrNotNil(t *testing.T) { @@ -69,8 +68,8 @@ func Test_startJobsOneJobErrNotNil(t *testing.T) { ) err := eflag.Parse() assert.NoError(t, err) - err = flag.Set("job", "test") - assert.NoError(t, err) + err1 := flag.Set("job", "test") + assert.NoError(t, err1) app := &Ego{ jobs: make(map[string]ejob.Ejob), @@ -80,8 +79,8 @@ func Test_startJobsOneJobErrNotNil(t *testing.T) { return fmt.Errorf("test") })) - err = app.startJobs() - assert.Equal(t, "test", err.Error()) + err2 := app.startJobs() + assert.Equal(t, "test", err2.Error()) } func resetFlagSet() { @@ -115,7 +114,7 @@ func Test_runSerialFuncReturnError(t *testing.T) { return nil }} err := runSerialFuncReturnError(args) - assert.Nil(t, err) + assert.NoError(t, err) args2 := []func() error{func() error { return fmt.Errorf("error") @@ -130,37 +129,33 @@ func Test_runSerialFuncLogError(t *testing.T) { }} runSerialFuncLogError(args) err := elog.EgoLogger.Flush() - if err != nil { - return - } + assert.NoError(t, err) filePath := path.Join(elog.EgoLogger.ConfigDir(), elog.EgoLogger.ConfigName()) - logged, err := ioutil.ReadFile(filePath) - assert.Nil(t, err) + logged, err1 := os.ReadFile(filePath) + assert.NoError(t, err1) assert.Contains(t, string(logged), `"Test_runSerialFuncLogError"`) } func Test_initLogger(t *testing.T) { app := &Ego{} err := os.Setenv(constant.EgoDebug, "true") - assert.Nil(t, err) + assert.NoError(t, err) cfg := ` [logger.default] debug = true enableAddCaller = true ` - err = econf.LoadFromReader(strings.NewReader(cfg), toml.Unmarshal) - assert.NoError(t, err) + err1 := econf.LoadFromReader(strings.NewReader(cfg), toml.Unmarshal) + assert.NoError(t, err1) - err = app.initLogger() - assert.Nil(t, err) + err2 := app.initLogger() + assert.NoError(t, err2) elog.Info("hello") - err1 := elog.DefaultLogger.Flush() - if err1 != nil { - return - } + err3 := elog.DefaultLogger.Flush() + assert.NoError(t, err3) filePath := path.Join(elog.DefaultLogger.ConfigDir(), elog.DefaultLogger.ConfigName()) - logged, err := os.ReadFile(filePath) - assert.Nil(t, err) + logged, err4 := os.ReadFile(filePath) + assert.NoError(t, err4) // 验证日志打印的caller是否正确 当前位置为ego/ego_function_test.go:150 assert.Contains(t, string(logged), "hello", `ego/ego_function_test.go:150`) } @@ -172,16 +167,14 @@ func Test_initSysLogger(t *testing.T) { err := econf.LoadFromReader(strings.NewReader(cfg), toml.Unmarshal) assert.NoError(t, err) - err = app.initLogger() - assert.Nil(t, err) + err1 := app.initLogger() + assert.NoError(t, err1) elog.EgoLogger.Info("hello1") - err1 := elog.EgoLogger.Flush() - if err1 != nil { - return - } + err2 := elog.EgoLogger.Flush() + assert.NoError(t, err2) filePath := path.Join(elog.EgoLogger.ConfigDir(), elog.EgoLogger.ConfigName()) - logged, err := os.ReadFile(filePath) - assert.Nil(t, err) + logged, err3 := os.ReadFile(filePath) + assert.NoError(t, err3) // 验证日志是否打印了hello assert.Contains(t, string(logged), "hello1") // 验证日志文件名是否为ego.sys @@ -198,16 +191,14 @@ func Test_initSysLogger(t *testing.T) { err := econf.LoadFromReader(strings.NewReader(cfg), toml.Unmarshal) assert.NoError(t, err) - err = app.initLogger() - assert.Nil(t, err) + err1 := app.initLogger() + assert.NoError(t, err1) elog.EgoLogger.Info("hello2") - err1 := elog.EgoLogger.Flush() - if err1 != nil { - return - } + err2 := elog.EgoLogger.Flush() + assert.NoError(t, err2) filePath := path.Join(elog.EgoLogger.ConfigDir(), elog.EgoLogger.ConfigName()) - logged, err := os.ReadFile(filePath) - assert.Nil(t, err) + logged, err3 := os.ReadFile(filePath) + assert.NoError(t, err3) // 验证日志是否打印了hello assert.Contains(t, string(logged), "hello2") // 验证日志文件名是否为ego.sys @@ -226,13 +217,14 @@ func Test_initSysLogger(t *testing.T) { err := econf.LoadFromReader(strings.NewReader(cfg), toml.Unmarshal) assert.NoError(t, err) - err = app.initLogger() - assert.Nil(t, err) + err1 := app.initLogger() + assert.NoError(t, err1) elog.EgoLogger.Info("hello3") - elog.EgoLogger.Flush() + err2 := elog.EgoLogger.Flush() + assert.NoError(t, err2) filePath := path.Join(elog.EgoLogger.ConfigDir(), elog.EgoLogger.ConfigName()) - logged, err := os.ReadFile(filePath) - assert.Nil(t, err) + logged, err3 := os.ReadFile(filePath) + assert.NoError(t, err3) // 验证日志是否打印了hello assert.Contains(t, string(logged), "hello3") // 验证日志文件名是否为ego.sys.log