Skip to content

Commit ba8c19c

Browse files
author
Pierre SOUCHAY
committed
test: added TestPGDatabaseTimeout to ensure our timing behaves as it should
Signed-off-by: Pierre Souchay <pierre.souchay@pelico.io>
1 parent 8d229a3 commit ba8c19c

File tree

2 files changed

+74
-2
lines changed

2 files changed

+74
-2
lines changed

collector/collector.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,6 @@ func (p PostgresCollector) Describe(ch chan<- *prometheus.Desc) {
178178

179179
// Collect implements the prometheus.Collector interface.
180180
func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) {
181-
ctx, cancel := context.WithTimeout(context.Background(), p.CollectionTimeout)
182-
defer cancel()
183181
// copy the instance so that concurrent scrapes have independent instances
184182
inst := p.instance.copy()
185183

@@ -190,6 +188,12 @@ func (p PostgresCollector) Collect(ch chan<- prometheus.Metric) {
190188
p.logger.Error("Error opening connection to database", "err", err)
191189
return
192190
}
191+
p.collectFromConnection(inst, ch)
192+
}
193+
194+
func (p PostgresCollector) collectFromConnection(inst *instance, ch chan<- prometheus.Metric) {
195+
ctx, cancel := context.WithTimeout(context.Background(), p.CollectionTimeout)
196+
defer cancel()
193197

194198
wg := sync.WaitGroup{}
195199
wg.Add(len(p.Collectors))

collector/pg_database_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,81 @@ package collector
1515
import (
1616
"context"
1717
"testing"
18+
"time"
1819

1920
"github.com/DATA-DOG/go-sqlmock"
2021
"github.com/prometheus/client_golang/prometheus"
22+
2123
dto "github.com/prometheus/client_model/go"
24+
"github.com/prometheus/common/promslog"
2225
"github.com/smartystreets/goconvey/convey"
2326
)
2427

28+
// We ensure that when the database respond after a long time
29+
// The collection process still occurs in a predictable manner
30+
// Will avoid accumulation of queries on a completely frozen DB
31+
func TestPGDatabaseTimeout(t *testing.T) {
32+
33+
timeoutForQuery := time.Duration(100 * time.Millisecond)
34+
35+
db, mock, err := sqlmock.New()
36+
if err != nil {
37+
t.Fatalf("Error opening a stub db connection: %s", err)
38+
}
39+
defer db.Close()
40+
41+
inst := &instance{db: db}
42+
43+
columns := []string{"pg_roles.rolname", "pg_roles.rolconnlimit"}
44+
rows := sqlmock.NewRows(columns).AddRow("role1", 2)
45+
mock.ExpectQuery(pgRolesConnectionLimitsQuery).
46+
WillDelayFor(30 * time.Second).
47+
WillReturnRows(rows)
48+
49+
log_config := promslog.Config{}
50+
51+
logger := promslog.New(&log_config)
52+
53+
c, err := NewPostgresCollector(logger, []string{}, "postgresql://local", []string{}, CollectionTimeout(timeoutForQuery.String()))
54+
if err != nil {
55+
t.Fatalf("error creating NewPostgresCollector: %s", err)
56+
}
57+
collector_config := collectorConfig{
58+
logger: logger,
59+
excludeDatabases: []string{},
60+
}
61+
62+
collector, err := NewPGRolesCollector(collector_config)
63+
if err != nil {
64+
t.Fatalf("error creating collector: %s", err)
65+
}
66+
c.Collectors["test"] = collector
67+
c.instance = inst
68+
69+
ch := make(chan prometheus.Metric)
70+
defer close(ch)
71+
72+
go func() {
73+
for {
74+
v := <-ch
75+
time.Sleep(1 * time.Millisecond)
76+
t.Logf("received metric %v", v.Desc().String())
77+
}
78+
}()
79+
80+
startTime := time.Now()
81+
c.collectFromConnection(inst, ch)
82+
elapsed := time.Since(startTime)
83+
84+
if elapsed <= timeoutForQuery {
85+
t.Errorf("elapsed time was %v, should be bigger than timeout=%v", elapsed, timeoutForQuery)
86+
}
87+
88+
if err := mock.ExpectationsWereMet(); err != nil {
89+
t.Errorf("there were unfulfilled exceptions: %s", err)
90+
}
91+
}
92+
2593
func TestPGDatabaseCollector(t *testing.T) {
2694
db, mock, err := sqlmock.New()
2795
if err != nil {

0 commit comments

Comments
 (0)