diff --git a/.golangci.yaml b/.golangci.yaml index 1995214e..d096ce92 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -74,6 +74,7 @@ linters-settings: - "github.com/prometheus/common/expfmt" - "github.com/panjf2000/gnet/v2" - "github.com/spf13/cobra" + - "github.com/knadh/koanf" tagalign: align: false sort: false diff --git a/Makefile b/Makefile index 21fb89b3..b66c1e09 100644 --- a/Makefile +++ b/Makefile @@ -110,6 +110,9 @@ clean: test: @go test -v ./... +benchmark: + @go test -bench=. -benchmem -run=^# ./... + update-all: @go get -u ./... @go mod tidy diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 00000000..391ad7ef --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,72 @@ +package config + +import ( + "context" + "testing" + + "github.com/knadh/koanf" + "github.com/stretchr/testify/assert" +) + +// TestNewConfig tests the NewConfig function. +func TestNewConfig(t *testing.T) { + config := NewConfig( + context.Background(), GlobalConfigFilename, PluginsConfigFilename) + assert.NotNil(t, config) + assert.Equal(t, config.globalConfigFile, GlobalConfigFilename) + assert.Equal(t, config.pluginConfigFile, PluginsConfigFilename) + assert.Equal(t, config.globalDefaults, GlobalConfig{}) + assert.Equal(t, config.pluginDefaults, PluginConfig{}) + assert.Equal(t, config.Global, GlobalConfig{}) + assert.Equal(t, config.Plugin, PluginConfig{}) + assert.Equal(t, config.GlobalKoanf, koanf.New(".")) + assert.Equal(t, config.PluginKoanf, koanf.New(".")) +} + +// TestInitConfig tests the InitConfig function, which practically tests all +// the other functions. +func TestInitConfig(t *testing.T) { + ctx := context.Background() + config := NewConfig(ctx, "../"+GlobalConfigFilename, "../"+PluginsConfigFilename) + config.InitConfig(ctx) + assert.NotNil(t, config.Global) + assert.NotEqual(t, config.Global, GlobalConfig{}) + assert.Contains(t, config.Global.Servers, Default) + assert.NotNil(t, config.Plugin) + assert.NotEqual(t, config.Plugin, PluginConfig{}) + assert.Len(t, config.Plugin.Plugins, 1) + assert.NotNil(t, config.GlobalKoanf) + assert.NotEqual(t, config.GlobalKoanf, koanf.New(".")) + assert.Equal(t, DefaultLogLevel, config.GlobalKoanf.String("loggers.default.level")) + assert.NotNil(t, config.PluginKoanf) + assert.NotEqual(t, config.PluginKoanf, koanf.New(".")) + assert.Equal(t, string(PassDown), config.PluginKoanf.String("verificationPolicy")) + assert.NotNil(t, config.globalDefaults) + assert.NotEqual(t, config.globalDefaults, GlobalConfig{}) + assert.Contains(t, config.globalDefaults.Servers, Default) + assert.NotNil(t, config.pluginDefaults) + assert.NotEqual(t, config.pluginDefaults, PluginConfig{}) + assert.Len(t, config.pluginDefaults.Plugins, 0) +} + +// TestMergeGlobalConfig tests the MergeGlobalConfig function. +func TestMergeGlobalConfig(t *testing.T) { + ctx := context.Background() + config := NewConfig(ctx, "../"+GlobalConfigFilename, "../"+PluginsConfigFilename) + config.InitConfig(ctx) + // The default log level is info. + assert.Equal(t, config.Global.Loggers[Default].Level, DefaultLogLevel) + + // Merge a config that sets the log level to debug. + config.MergeGlobalConfig(ctx, map[string]interface{}{ + "loggers": map[string]interface{}{ + "default": map[string]interface{}{ + "level": "debug", + }, + }, + }) + assert.NotNil(t, config.Global) + assert.NotEqual(t, config.Global, GlobalConfig{}) + // The log level should now be debug. + assert.Equal(t, config.Global.Loggers[Default].Level, "debug") +} diff --git a/config/getters.go b/config/getters.go index 5140437d..2b2f6950 100644 --- a/config/getters.go +++ b/config/getters.go @@ -207,6 +207,11 @@ func (l Logger) GetOutput() []LogOutput { outputs = append(outputs, Console) } } + + if len(outputs) == 0 { + outputs = append(outputs, Console) + } + return outputs } diff --git a/config/getters_test.go b/config/getters_test.go new file mode 100644 index 00000000..3ec6bf09 --- /dev/null +++ b/config/getters_test.go @@ -0,0 +1,130 @@ +package config + +import ( + "testing" + "time" + + "github.com/panjf2000/gnet/v2" + "github.com/rs/zerolog" + "github.com/stretchr/testify/assert" +) + +// TestGetVerificationPolicy tests the GetVerificationPolicy function. +func TestGetVerificationPolicy(t *testing.T) { + pluginConfig := PluginConfig{} + assert.Equal(t, PassDown, pluginConfig.GetVerificationPolicy()) +} + +// TestGetPluginCompatibilityPolicy tests the GetPluginCompatibilityPolicy function. +func TestGetPluginCompatibilityPolicy(t *testing.T) { + pluginConfig := PluginConfig{} + assert.Equal(t, Strict, pluginConfig.GetPluginCompatibilityPolicy()) +} + +// TestGetAcceptancePolicy tests the GetAcceptancePolicy function. +func TestGetAcceptancePolicy(t *testing.T) { + pluginConfig := PluginConfig{} + assert.Equal(t, Accept, pluginConfig.GetAcceptancePolicy()) +} + +// TestGetTerminationPolicy tests the GetTerminationPolicy function. +func TestGetTerminationPolicy(t *testing.T) { + pluginConfig := PluginConfig{} + assert.Equal(t, Stop, pluginConfig.GetTerminationPolicy()) +} + +// TestGetTCPKeepAlivePeriod tests the GetTCPKeepAlivePeriod function. +func TestGetTCPKeepAlivePeriod(t *testing.T) { + client := Client{} + assert.Equal(t, DefaultTCPKeepAlivePeriod, client.GetTCPKeepAlivePeriod()) +} + +// TestGetReceiveDeadline tests the GetReceiveDeadline function. +func TestGetReceiveDeadline(t *testing.T) { + client := Client{} + assert.Equal(t, time.Duration(0), client.GetReceiveDeadline()) +} + +// TestGetReceiveTimeout tests the GetReceiveTimeout function. +func TestGetReceiveTimeout(t *testing.T) { + client := Client{} + assert.Equal(t, time.Duration(0), client.GetReceiveTimeout()) +} + +// TestGetSendDeadline tests the GetSendDeadline function. +func TestGetSendDeadline(t *testing.T) { + client := Client{} + assert.Equal(t, time.Duration(0), client.GetSendDeadline()) +} + +// TestGetReceiveChunkSize tests the GetReceiveChunkSize function. +func TestGetReceiveChunkSize(t *testing.T) { + client := Client{} + assert.Equal(t, DefaultChunkSize, client.GetReceiveChunkSize()) +} + +// TestGetHealthCheckPeriod tests the GetHealthCheckPeriod function. +func TestGetHealthCheckPeriod(t *testing.T) { + proxy := Proxy{} + assert.Equal(t, DefaultHealthCheckPeriod, proxy.GetHealthCheckPeriod()) +} + +// TestGetTickInterval tests the GetTickInterval function. +func TestGetTickInterval(t *testing.T) { + server := Server{} + assert.Equal(t, DefaultTickInterval, server.GetTickInterval()) +} + +// TestGetLoadBalancer tests the GetLoadBalancer function. +func TestGetLoadBalancer(t *testing.T) { + server := Server{} + assert.Equal(t, gnet.RoundRobin, server.GetLoadBalancer()) +} + +// TestGetTCPNoDelay tests the GetTCPNoDelay function. +func TestGetTCPNoDelay(t *testing.T) { + server := Server{} + assert.Equal(t, gnet.TCPDelay, server.GetTCPNoDelay()) +} + +// TestGetSize tests the GetSize function. +func TestGetSize(t *testing.T) { + pool := Pool{} + assert.Equal(t, DefaultPoolSize, pool.GetSize()) +} + +// TestGetOutput tests the GetOutput function. +func TestGetOutput(t *testing.T) { + logger := Logger{} + assert.Equal(t, []LogOutput{Console}, logger.GetOutput()) +} + +// TestGetTimeFormat tests the GetTimeFormat function. +func TestGetTimeFormat(t *testing.T) { + logger := Logger{} + assert.Equal(t, zerolog.TimeFormatUnix, logger.GetTimeFormat()) +} + +// TestGetConsoleTimeFormat tests the GetConsoleTimeFormat function. +func TestGetConsoleTimeFormat(t *testing.T) { + logger := Logger{} + assert.Equal(t, time.RFC3339, logger.GetConsoleTimeFormat()) +} + +// TestGetLevel tests the GetLevel function. +func TestGetLevel(t *testing.T) { + logger := Logger{} + assert.Equal(t, zerolog.InfoLevel, logger.GetLevel()) +} + +// TestGetPlugins tests the GetPlugins function. +func TestGetPlugins(t *testing.T) { + plugin := Plugin{Name: "plugin1"} + pluginConfig := PluginConfig{Plugins: []Plugin{plugin}} + assert.Equal(t, []Plugin{plugin}, pluginConfig.GetPlugins("plugin1")) +} + +// TestGetDefaultConfigFilePath tests the GetDefaultConfigFilePath function. +func TestGetDefaultConfigFilePath(t *testing.T) { + assert.Equal(t, GlobalConfigFilename, GetDefaultConfigFilePath(GlobalConfigFilename)) +} diff --git a/config/version_test.go b/config/version_test.go new file mode 100644 index 00000000..538a18cf --- /dev/null +++ b/config/version_test.go @@ -0,0 +1,18 @@ +package config + +import ( + "runtime" + "testing" + + "github.com/stretchr/testify/assert" +) + +// TestVersionInfo tests the VersionInfo function. +func TestVersionInfo(t *testing.T) { + versionInfo := VersionInfo() + assert.Contains(t, versionInfo, "GatewayD") + assert.Contains(t, versionInfo, "0.0.0") + assert.Contains(t, versionInfo, "go") + assert.Contains(t, versionInfo, runtime.GOOS) + assert.Contains(t, versionInfo, runtime.GOARCH) +} diff --git a/network/client_test.go b/network/client_test.go index 99bc70c5..91789295 100644 --- a/network/client_test.go +++ b/network/client_test.go @@ -106,3 +106,115 @@ func TestIsConnected(t *testing.T) { client.Close() assert.False(t, client.IsConnected()) } + +func BenchmarkNewClient(b *testing.B) { + cfg := logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + } + + logger := logging.NewLogger(context.Background(), cfg) + for i := 0; i < b.N; i++ { + client := NewClient(context.Background(), &config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + }, logger) + client.Close() + } +} + +func BenchmarkSend(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + }) + + client := NewClient( + context.Background(), + &config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + }, + logger) + defer client.Close() + + packet := CreatePgStartupPacket() + for i := 0; i < b.N; i++ { + client.Send(packet) //nolint:errcheck + } +} + +func BenchmarkReceive(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + }) + + client := NewClient( + context.Background(), + &config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + ReceiveTimeout: 1 * time.Millisecond, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + }, + logger) + defer client.Close() + + packet := CreatePgStartupPacket() + client.Send(packet) //nolint:errcheck + for i := 0; i < b.N; i++ { + client.Receive() //nolint:errcheck + } +} + +func BenchmarkIsConnected(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + }) + + client := NewClient( + context.Background(), + &config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + }, + logger) + defer client.Close() + + for i := 0; i < b.N; i++ { + client.IsConnected() + } +} diff --git a/network/proxy_test.go b/network/proxy_test.go index b7a50c29..770cada6 100644 --- a/network/proxy_test.go +++ b/network/proxy_test.go @@ -126,3 +126,306 @@ func TestNewProxyElastic(t *testing.T) { assert.Equal(t, "tcp", proxy.ClientConfig.Network) assert.Equal(t, "localhost:5432", proxy.ClientConfig.Address) } + +func BenchmarkNewProxy(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.WarnLevel, + NoColor: true, + }) + + // Create a connection pool + pool := pool.NewPool(context.Background(), config.EmptyPoolCapacity) + + // Create a proxy with a fixed buffer pool + for i := 0; i < b.N; i++ { + proxy := NewProxy( + context.Background(), + pool, + plugin.NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ), + false, + false, + config.DefaultHealthCheckPeriod, + nil, + logger, + config.DefaultPluginTimeout) + proxy.Shutdown() + } +} + +func BenchmarkNewProxyElastic(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.WarnLevel, + NoColor: true, + }) + + // Create a connection pool + pool := pool.NewPool(context.Background(), config.EmptyPoolCapacity) + + // Create a proxy with an elastic buffer pool + for i := 0; i < b.N; i++ { + proxy := NewProxy( + context.Background(), + pool, + plugin.NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ), + true, + false, + config.DefaultHealthCheckPeriod, + &config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + }, + logger, + config.DefaultPluginTimeout) + proxy.Shutdown() + } +} + +func BenchmarkProxyConnectDisconnect(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.PanicLevel, + NoColor: true, + }) + + // Create a connection pool + pool := pool.NewPool(context.Background(), 1) + + clientConfig := config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + ReceiveTimeout: config.DefaultReceiveTimeout, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + } + pool.Put("client", NewClient(context.Background(), &clientConfig, logger)) //nolint:errcheck + + // Create a proxy with a fixed buffer pool + proxy := NewProxy( + context.Background(), + pool, + plugin.NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ), + false, + false, + config.DefaultHealthCheckPeriod, + &clientConfig, + logger, + config.DefaultPluginTimeout) + defer proxy.Shutdown() + + gconn := testGNetConnection{} + + // Connect to the proxy + for i := 0; i < b.N; i++ { + proxy.Connect(gconn.Conn) //nolint:errcheck + proxy.Disconnect(&gconn) //nolint:errcheck + } +} + +func BenchmarkProxyPassThrough(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.PanicLevel, + NoColor: true, + }) + + // Create a connection pool + pool := pool.NewPool(context.Background(), 1) + + clientConfig := config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + ReceiveTimeout: config.DefaultReceiveTimeout, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + } + pool.Put("client", NewClient(context.Background(), &clientConfig, logger)) //nolint:errcheck + + // Create a proxy with a fixed buffer pool + proxy := NewProxy( + context.Background(), + pool, + plugin.NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ), + false, + false, + config.DefaultHealthCheckPeriod, + &clientConfig, + logger, + config.DefaultPluginTimeout) + defer proxy.Shutdown() + + gconn := testGNetConnection{} + proxy.Connect(gconn.Conn) //nolint:errcheck + defer proxy.Disconnect(&gconn) //nolint:errcheck + + // Connect to the proxy + for i := 0; i < b.N; i++ { + proxy.PassThrough(&gconn) //nolint:errcheck + } +} + +func BenchmarkProxyIsHealthyAndIsExhausted(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.PanicLevel, + NoColor: true, + }) + + // Create a connection pool + pool := pool.NewPool(context.Background(), 1) + + clientConfig := config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + ReceiveTimeout: config.DefaultReceiveTimeout, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + } + client := NewClient(context.Background(), &clientConfig, logger) + pool.Put("client", client) //nolint:errcheck + + // Create a proxy with a fixed buffer pool + proxy := NewProxy( + context.Background(), + pool, + plugin.NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ), + false, + false, + config.DefaultHealthCheckPeriod, + &clientConfig, + logger, + config.DefaultPluginTimeout) + defer proxy.Shutdown() + + gconn := testGNetConnection{} + proxy.Connect(gconn.Conn) //nolint:errcheck + defer proxy.Disconnect(&gconn) //nolint:errcheck + + // Connect to the proxy + for i := 0; i < b.N; i++ { + proxy.IsHealty(client) //nolint:errcheck + proxy.IsExhausted() + } +} + +func BenchmarkProxyAvailableAndBusyConnections(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.PanicLevel, + NoColor: true, + }) + + // Create a connection pool + pool := pool.NewPool(context.Background(), 1) + + clientConfig := config.Client{ + Network: "tcp", + Address: "localhost:5432", + ReceiveChunkSize: config.DefaultChunkSize, + ReceiveDeadline: config.DefaultReceiveDeadline, + ReceiveTimeout: config.DefaultReceiveTimeout, + SendDeadline: config.DefaultSendDeadline, + TCPKeepAlive: false, + TCPKeepAlivePeriod: config.DefaultTCPKeepAlivePeriod, + } + client := NewClient(context.Background(), &clientConfig, logger) + pool.Put("client", client) //nolint:errcheck + + // Create a proxy with a fixed buffer pool + proxy := NewProxy( + context.Background(), + pool, + plugin.NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ), + false, + false, + config.DefaultHealthCheckPeriod, + &clientConfig, + logger, + config.DefaultPluginTimeout) + defer proxy.Shutdown() + + gconn := testGNetConnection{} + proxy.Connect(gconn.Conn) //nolint:errcheck + defer proxy.Disconnect(&gconn) //nolint:errcheck + + // Connect to the proxy + for i := 0; i < b.N; i++ { + proxy.AvailableConnections() + proxy.BusyConnections() + } +} diff --git a/network/utils.go b/network/utils.go index 80af2092..ff85f337 100644 --- a/network/utils.go +++ b/network/utils.go @@ -74,7 +74,6 @@ func trafficData( } for _, field := range fields { - // field.Value will be converted to base64-encoded string. data[field.Name] = field.Value } diff --git a/network/utils_test.go b/network/utils_test.go index 6fe5e595..2ab4f0d4 100644 --- a/network/utils_test.go +++ b/network/utils_test.go @@ -2,11 +2,15 @@ package network import ( "context" + "fmt" + "math/big" + "net" "testing" "time" "github.com/gatewayd-io/gatewayd/config" "github.com/gatewayd-io/gatewayd/logging" + "github.com/panjf2000/gnet/v2" "github.com/rs/zerolog" "github.com/stretchr/testify/assert" ) @@ -41,3 +45,131 @@ func TestResolve(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "127.0.0.1:53", address) } + +var seedValues = []int{1000, 10000, 100000, 1000000, 10000000} + +func BenchmarkGetID(b *testing.B) { + cfg := logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + } + + logger := logging.NewLogger(context.Background(), cfg) + for _, seed := range seedValues { + b.Run(fmt.Sprintf("seed=%d", seed), func(b *testing.B) { + for i := 0; i < b.N; i++ { + GetID("tcp", "localhost:5432", seed, logger) + } + }) + } +} + +func BenchmarkResolveUDP(b *testing.B) { + cfg := logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + } + + logger := logging.NewLogger(context.Background(), cfg) + for i := 0; i < b.N; i++ { + Resolve("udp", "localhost:53", logger) //nolint:errcheck + } +} + +func BenchmarkResolveTCP(b *testing.B) { + cfg := logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + } + + logger := logging.NewLogger(context.Background(), cfg) + for i := 0; i < b.N; i++ { + Resolve("tcp", "localhost:5432", logger) //nolint:errcheck + } +} + +func BenchmarkResolveUnix(b *testing.B) { + cfg := logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + } + + logger := logging.NewLogger(context.Background(), cfg) + for i := 0; i < b.N; i++ { + Resolve("unix", "/tmp/unix.sock", logger) //nolint:errcheck + } +} + +type testGNetConnection struct { + gnet.Conn +} + +func (c *testGNetConnection) LocalAddr() net.Addr { + return &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 0, + } +} + +func (c *testGNetConnection) RemoteAddr() net.Addr { + return &net.TCPAddr{ + IP: net.ParseIP("127.0.0.1"), + Port: 0, + } +} + +func BenchmarkTrafficData(b *testing.B) { + logger := logging.NewLogger(context.Background(), logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + }) + + gconn := &testGNetConnection{} + client := NewClient(context.Background(), &config.Client{ + Network: "tcp", + Address: "localhost:5432", + TCPKeepAlive: false, + TCPKeepAlivePeriod: time.Second * 10, + ReceiveChunkSize: 1024, + }, logger) + fields := []Field{ + { + Name: "test", + Value: []byte("test"), + }, + { + Name: "test2", + Value: big.NewInt(123456).Bytes(), + }, + } + err := "test error" + for i := 0; i < b.N; i++ { + trafficData(gconn, client, fields, err) + } +} + +func BenchmarkExtractFieldValue(b *testing.B) { + for i := 0; i < b.N; i++ { + extractFieldValue( + map[string]interface{}{ + "test": "test", + }, + "test", + ) + } +} diff --git a/plugin/plugin_registry_test.go b/plugin/plugin_registry_test.go index ab73342b..7a4b2eb2 100644 --- a/plugin/plugin_registry_test.go +++ b/plugin/plugin_registry_test.go @@ -293,3 +293,46 @@ func Test_HookRegistry_Run_Remove(t *testing.T) { assert.Equal(t, map[string]interface{}{}, result) assert.Equal(t, 1, len(reg.Hooks()[v1.HookName_HOOK_NAME_ON_NEW_LOGGER])) } + +func BenchmarkHookRun(b *testing.B) { + cfg := logging.LoggerConfig{ + Output: []config.LogOutput{config.Console}, + TimeFormat: zerolog.TimeFormatUnix, + ConsoleTimeFormat: time.RFC3339, + Level: zerolog.DebugLevel, + NoColor: true, + } + logger := logging.NewLogger(context.Background(), cfg) + reg := NewRegistry( + context.Background(), + config.Loose, + config.PassDown, + config.Accept, + config.Stop, + logger, + false, + ) + reg.Verification = config.PassDown + hookFunction := func( + ctx context.Context, args *v1.Struct, opts ...grpc.CallOption, + ) (*v1.Struct, error) { + args.Fields["test"] = v1.NewStringValue("test1") + return args, nil + } + for priority := 0; priority < 1000; priority++ { + reg.AddHook(v1.HookName_HOOK_NAME_ON_NEW_LOGGER, + sdkPlugin.Priority(priority), + hookFunction, + ) + } + for i := 0; i < b.N; i++ { + //nolint:errcheck + reg.Run( + context.Background(), + map[string]interface{}{ + "test": "test", + }, + v1.HookName_HOOK_NAME_ON_NEW_LOGGER, + ) + } +} diff --git a/pool/pool_test.go b/pool/pool_test.go index e406d11e..dbb2ada6 100644 --- a/pool/pool_test.go +++ b/pool/pool_test.go @@ -224,3 +224,84 @@ func TestPool_Cap(t *testing.T) { assert.Equal(t, 0, pool.Size()) assert.Equal(t, 1, pool.Cap()) } + +func BenchmarkNewPool(b *testing.B) { + for i := 0; i < b.N; i++ { + NewPool(context.Background(), config.EmptyPoolCapacity) + } +} + +func BenchmarkPool_PutPop(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + for i := 0; i < b.N; i++ { + pool.Put("client1.ID", "client1") //nolint:errcheck + pool.Pop("client1.ID") + } +} + +func BenchmarkPool_Clear(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + for i := 0; i < b.N; i++ { + pool.Clear() + } +} + +func BenchmarkPool_ForEach(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + pool.Put("client1.ID", "client1") //nolint:errcheck + pool.Put("client2.ID", "client2") //nolint:errcheck + for i := 0; i < b.N; i++ { + pool.ForEach(func(key, value interface{}) bool { + return true + }) + } +} + +func BenchmarkPool_Get(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + pool.Put("client1.ID", "client1") //nolint:errcheck + pool.Put("client2.ID", "client2") //nolint:errcheck + for i := 0; i < b.N; i++ { + pool.Get("client1.ID") + pool.Get("client2.ID") + } +} + +func BenchmarkPool_GetOrPut(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + pool.Put("client1.ID", "client1") //nolint:errcheck + pool.Put("client2.ID", "client2") //nolint:errcheck + for i := 0; i < b.N; i++ { + pool.GetOrPut("client1.ID", "client1") //nolint:errcheck + pool.GetOrPut("client2.ID", "client2") //nolint:errcheck + } +} + +func BenchmarkPool_Remove(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + for i := 0; i < b.N; i++ { + pool.Put("client1.ID", "client1") //nolint:errcheck + pool.Remove("client1.ID") + } +} + +func BenchmarkPool_Size(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + for i := 0; i < b.N; i++ { + pool.Size() + } +} + +func BenchmarkPool_Cap(b *testing.B) { + pool := NewPool(context.Background(), config.EmptyPoolCapacity) + defer pool.Clear() + for i := 0; i < b.N; i++ { + pool.Cap() + } +}