Skip to content

Commit f3a2ef0

Browse files
calvinrzachmanGeorgeTsagk
authored andcommitted
loadtest: add support for push metrics
Equip the test orchestrator with the ability to push metrics on execution time to a configurable remote prometheus push gateway.
1 parent 72b93f8 commit f3a2ef0

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

itest/loadtest/config.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ type BitcoinConfig struct {
5858
TLSPath string `long:"tlspath" description:"Path to btcd's TLS certificate, if TLS is enabled"`
5959
}
6060

61+
// PrometheusGatewayConfig defines exported config options for connecting to the
62+
// Prometheus PushGateway.
63+
type PrometheusGatewayConfig struct {
64+
// nolint: lll
65+
Enabled bool `long:"enabled" description:"Enable pushing metrics to Prometheus PushGateway"`
66+
// nolint: lll
67+
Host string `long:"host" description:"Prometheus PushGateway host address"`
68+
Port int `long:"port" description:"Prometheus PushGateway port"`
69+
PushURL string
70+
}
71+
6172
// Config holds the main configuration for the performance testing binary.
6273
type Config struct {
6374
// TestCases is a comma separated list of test cases that will be
@@ -97,6 +108,12 @@ type Config struct {
97108

98109
// TestTimeout is the timeout for each test.
99110
TestTimeout time.Duration `long:"test-timeout" description:"the timeout for each test"`
111+
112+
// PrometheusGateway is the configuration for the Prometheus
113+
// PushGateway.
114+
//
115+
// nolint: lll
116+
PrometheusGateway *PrometheusGatewayConfig `group:"prometheus-gateway" namespace:"prometheus-gateway" description:"Prometheus PushGateway configuration"`
100117
}
101118

102119
// DefaultConfig returns the default configuration for the performance testing
@@ -120,6 +137,11 @@ func DefaultConfig() Config {
120137
SendType: taprpc.AssetType_COLLECTIBLE,
121138
TestSuiteTimeout: defaultSuiteTimeout,
122139
TestTimeout: defaultTestTimeout,
140+
PrometheusGateway: &PrometheusGatewayConfig{
141+
Enabled: false,
142+
Host: "localhost",
143+
Port: 9091,
144+
},
123145
}
124146
}
125147

@@ -156,6 +178,28 @@ func LoadConfig() (*Config, error) {
156178
// of it with sane defaults.
157179
func ValidateConfig(cfg Config) (*Config, error) {
158180
// TODO (positiveblue): add validation logic.
181+
182+
// Validate Prometheus PushGateway configuration.
183+
if cfg.PrometheusGateway.Enabled {
184+
gatewayHost := cfg.PrometheusGateway.Host
185+
gatewayPort := cfg.PrometheusGateway.Port
186+
187+
if gatewayHost == "" {
188+
return nil, fmt.Errorf(
189+
"gateway hostname may not be empty",
190+
)
191+
}
192+
193+
if gatewayPort == 0 {
194+
return nil, fmt.Errorf("gateway port is not set")
195+
}
196+
197+
// Construct the endpoint for Prometheus PushGateway.
198+
cfg.PrometheusGateway.PushURL = fmt.Sprintf(
199+
"%s:%d", gatewayHost, gatewayPort,
200+
)
201+
}
202+
159203
return &cfg, nil
160204
}
161205

itest/loadtest/load_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,30 @@ package loadtest
44

55
import (
66
"context"
7+
"fmt"
78
"testing"
9+
"time"
810

11+
"github.com/prometheus/client_golang/prometheus"
12+
"github.com/prometheus/client_golang/prometheus/push"
913
"github.com/stretchr/testify/require"
1014
)
1115

16+
var (
17+
testDuration = prometheus.NewGaugeVec(
18+
prometheus.GaugeOpts{
19+
Name: "test_duration_seconds",
20+
Help: "Duration of the test execution, in seconds",
21+
},
22+
[]string{"test_name"},
23+
)
24+
)
25+
26+
func init() {
27+
// Register the metric with Prometheus's default registry.
28+
prometheus.MustRegister(testDuration)
29+
}
30+
1231
type testCase struct {
1332
name string
1433
fn func(t *testing.T, ctx context.Context, cfg *Config)
@@ -48,6 +67,9 @@ func TestPerformance(t *testing.T) {
4867
continue
4968
}
5069

70+
// Record the start time of the test case.
71+
startTime := time.Now()
72+
5173
success := t.Run(tc.name, func(tt *testing.T) {
5274
ctxt, cancel := context.WithTimeout(
5375
ctxt, cfg.TestTimeout,
@@ -59,6 +81,33 @@ func TestPerformance(t *testing.T) {
5981
if !success {
6082
t.Fatalf("test case %v failed", tc.name)
6183
}
84+
85+
// Calculate the test duration and push metrics if the test case succeeded.
86+
if cfg.PrometheusGateway.Enabled {
87+
duration := time.Since(startTime).Seconds()
88+
89+
timeTag := fmt.Sprintf("%d", time.Now().Unix())
90+
91+
label := tc.name + timeTag
92+
93+
// Update the metric with the test duration.
94+
testDuration.WithLabelValues(label).Set(duration)
95+
96+
t.Logf("Pushing testDuration %v with label %v to gateway", duration, label)
97+
98+
// Create a new pusher to push the metrics.
99+
pusher := push.New(cfg.PrometheusGateway.PushURL, "load_test").
100+
Collector(testDuration)
101+
102+
// Push the metrics to Prometheus PushGateway.
103+
if err := pusher.Add(); err != nil {
104+
t.Logf("Could not push metrics to Prometheus PushGateway: %v",
105+
err)
106+
} else {
107+
t.Logf("Metrics pushed for test case '%s': duration = %v seconds",
108+
tc.name, duration)
109+
}
110+
}
62111
}
63112
}
64113

0 commit comments

Comments
 (0)