diff --git a/itest/loadtest/config.go b/itest/loadtest/config.go index ac133d418..c27d8d79d 100644 --- a/itest/loadtest/config.go +++ b/itest/loadtest/config.go @@ -1,6 +1,7 @@ package loadtest import ( + "fmt" "time" "github.com/jessevdk/go-flags" @@ -44,6 +45,15 @@ type BitcoinConfig struct { TLSPath string `long:"tlspath" description:"Path to btcd's TLS certificate, if TLS is enabled"` } +// PrometheusGatewayConfig defines exported config options for connecting to the +// Prometheus PushGateway. +type PrometheusGatewayConfig struct { + Enabled bool `long:"enabled" description:"Enable pushing metrics to Prometheus PushGateway"` + Host string `long:"host" description:"Prometheus PushGateway host address"` + Port int `long:"port" description:"Prometheus PushGateway port"` + PushURL string +} + // Config holds the main configuration for the performance testing binary. type Config struct { // TestCases is a comma separated list of test cases that will be @@ -80,6 +90,9 @@ type Config struct { // TestTimeout is the timeout for each test. TestTimeout time.Duration `long:"test-timeout" description:"the timeout for each test"` + + // PrometheusGateway is the configuration for the Prometheus PushGateway. + PrometheusGateway *PrometheusGatewayConfig `group:"prometheus-gateway" namespace:"prometheus-gateway" description:"Prometheus PushGateway configuration"` } // DefaultConfig returns the default configuration for the performance testing @@ -102,6 +115,11 @@ func DefaultConfig() Config { SendType: taprpc.AssetType_COLLECTIBLE, TestSuiteTimeout: defaultSuiteTimeout, TestTimeout: defaultTestTimeout, + PrometheusGateway: &PrometheusGatewayConfig{ + Enabled: false, + Host: "localhost", + Port: 9091, + }, } } @@ -138,5 +156,25 @@ func LoadConfig() (*Config, error) { // of it with sane defaults. func ValidateConfig(cfg Config) (*Config, error) { // TODO (positiveblue): add validation logic. + + // Validate Prometheus PushGateway configuration. + if cfg.PrometheusGateway.Enabled { + gatewayHost := cfg.PrometheusGateway.Host + gatewayPort := cfg.PrometheusGateway.Port + + if gatewayHost == "" { + return nil, fmt.Errorf("gateway hostname may not be empty") + } + + if gatewayPort == 0 { + return nil, fmt.Errorf("gateway port is not set") + } + + // Construct the endpoint for Prometheus PushGateway. + cfg.PrometheusGateway.PushURL = fmt.Sprintf( + "%s:%d", gatewayHost, gatewayPort, + ) + } + return &cfg, nil } diff --git a/itest/loadtest/load_test.go b/itest/loadtest/load_test.go index 1d32a83b8..0017a96a0 100644 --- a/itest/loadtest/load_test.go +++ b/itest/loadtest/load_test.go @@ -5,10 +5,28 @@ package loadtest import ( "context" "testing" + "time" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/push" "github.com/stretchr/testify/require" ) +var ( + testDuration = prometheus.NewGaugeVec( + prometheus.GaugeOpts{ + Name: "test_duration_seconds", + Help: "Duration of the test execution, in seconds", + }, + []string{"test_name"}, + ) +) + +func init() { + // Register the metric with Prometheus's default registry. + prometheus.MustRegister(testDuration) +} + type testCase struct { name string fn func(t *testing.T, ctx context.Context, cfg *Config) @@ -44,6 +62,9 @@ func TestPerformance(t *testing.T) { continue } + // Record the start time of the test case. + startTime := time.Now() + success := t.Run(tc.name, func(tt *testing.T) { ctxt, cancel := context.WithTimeout( ctxt, cfg.TestTimeout, @@ -55,6 +76,28 @@ func TestPerformance(t *testing.T) { if !success { t.Fatalf("test case %v failed", tc.name) } + + // Calculate the test duration and push metrics if the test case succeeded. + if cfg.PrometheusGateway.Enabled { + duration := time.Since(startTime).Seconds() + + // Update the metric with the test duration. + testDuration.WithLabelValues(tc.name).Set(duration) + + // Create a new pusher to push the metrics. + pusher := push.New(cfg.PrometheusGateway.PushURL, "load_test"). + Collector(testDuration). + Grouping("test_case", tc.name) + + // Push the metrics to Prometheus PushGateway. + if err := pusher.Push(); err != nil { + t.Logf("Could not push metrics to Prometheus PushGateway: %v", + err) + } else { + t.Logf("Metrics pushed for test case '%s': duration = %v seconds", + tc.name, duration) + } + } } }